如果在循环条件下使用,strlen会被多次计算吗?
我不确定以下代码是否会导致冗余计算,还是编译器特定的?
for (int i = 0; i < strlen(ss); ++i) { // blabla }
每次i
增加时都会计算strlen()
吗?
是的, strlen()
将在每次迭代中被评估。 有可能在理想情况下,优化器可能会推断出价值不会改变,但我个人不会依赖这个。
我会做一些像
for (int i = 0, n = strlen(ss); i < n; ++i)
或者可能
for (int i = 0; ss[i]; ++i)
只要string在迭代期间不会改变长度。 如果可能,那么你需要每次调用strlen()
,或者通过更复杂的逻辑来处理它。
是的,每次使用循环。 然后每次计算string的长度。 所以像这样使用它:
char str[30]; for ( int i = 0; str[i] != '\0'; i++) { //Something; }
在上面的代码中, str[i]
只在每次循环开始一个循环时validation位置i
中的string中的一个特定字符,因此它将占用较less的内存并且更高效。
看到这个链接了解更多信息。
在下面的代码中,每次循环运行时, strlen
都会计算整个string的长度,效率更低,花费更多的时间和更多的内存。
char str[]; for ( int i = 0; i < strlen(str); i++) { //Something; }
一个好的编译器可能不会每次计算它,但是我不认为你可以确定每个编译器都这么做。
除此之外,编译器必须知道,strlen(ss)不会改变。 只有在for循环中没有改变ss时,这才是真实的。
例如,如果在for循环的ss中使用只读函数,但不要将ss参数声明为const,那么编译器甚至不能知道该循环中ss是否被更改,并且必须计算strlen( ss)在每个迭代中
如果ss
的types是const char *
并且不是在循环中强制转换,那么编译器可能只会调用strlen
一次,如果优化打开的话。 但这当然不是可以指望的行为。
您应该将strlen
结果保存在一个variables中,并在循环中使用该variables。 如果你不想创build一个额外的variables,取决于你在做什么,你可能会脱胎换骨,以反向迭代。
for( auto i = strlen(s); i > 0; --i ) { // do whatever // remember value of s[strlen(s)] is the terminating NULL character }
正式是, strlen()
预计将被调用每个迭代。
无论如何,我不想否定一些聪明的编译器优化的存在的可能性,这将优化掉第一个之后的任何连续调用strlen()。
整个谓词代码将在for
循环的每次迭代中执行。 为了记忆strlen(ss)
调用的结果,编译器至less需要知道
- 函数
strlen
是无副作用的 - 由
ss
指向的内存在循环的持续时间内不会改变
编译器不知道这些事情,因此不能安全地记忆第一次调用的结果
是的,每当代码运行时,strlen(ss)都会被计算出来。
是的, strlen(ss)
会计算每次迭代的长度。 如果你通过某种方式增加ss
,并增加i
; 会有无限的循环。
是的, 每次评估循环时都会调用strlen()
函数。
如果你想提高效率,那么一定要记住将所有内容保存在局部variables中……这将需要时间,但是非常有用。
你可以使用下面的代码:
String str="ss"; int l = strlen(str); for ( int i = 0; i < l ; i++ ) { // blablabla }
现在不常见,但20年前在16位平台上,我build议这样做:
for(char * p = str; * p; p ++){}
如果你的编译器在优化方面不是很聪明的话,上面的代码可以产生很好的汇编代码。
是。 testing不知道ss在循环内部没有改变。 如果你知道它不会改变,那么我会写:
int stringLength = strlen (ss); for ( int i = 0; i < stringLength; ++ i ) { // blabla }
是的 。 每增加一次,strlen就会被计算出来。
如果你没有改变 循环意味着它不会影响逻辑,否则会影响。
使用下面的代码更安全。
int length = strlen(ss); for ( int i = 0; i < length ; ++ i ) { // blabla }
是的,用简单的话来说。 在编译器希望的极less情况下,如果发现ss
完全没有改变,就作为优化步骤。 但在安全的情况下,你应该认为是的。 在multithreaded
和事件驱动的程序中有一些情况,如果你认为它是NO,它可能会出错。 因为它不会太多地提高程序的复杂性,所以玩起来很安全。
是。
strlen()
计算每当i
增加,并没有优化。
下面的代码显示了为什么编译器不应该优化strlen()
。
for ( int i = 0; i < strlen(ss); ++i ) { // Change ss string. ss[i] = 'a'; // Compiler should not optimize strlen(). }
我们可以很容易地testing它:
char nums[] = "0123456789"; size_t end; int i; for( i=0, end=strlen(nums); i<strlen(nums); i++ ) { putchar( nums[i] ); num[--end] = 0; }
循环条件在每次重复之后,在重新启动循环之前进行评估。
另外要小心你用来处理string长度的types。 它应该是在stdio中被定义为unsigned int
size_t
。 比较并将其转换为int
可能会导致一些严重的漏洞问题。
好吧,我注意到有人说这是由任何“聪明”的现代编译器默认优化。 顺便看看没有优化的结果。 我试过了:
最小的C代码:
#include <stdio.h> #include <string.h> int main() { char *s="aaaa"; for (int i=0; i<strlen(s);i++) printf ("a"); return 0; }
我的编译器:g ++(Ubuntu / Linaro 4.6.3-1ubuntu5)4.6.3
生成汇编代码的命令:g ++ -S -masm = intel test.cpp
Gotten assembly code at the output: ... L3: mov DWORD PTR [esp], 97 call putchar add DWORD PTR [esp+40], 1 .L2: THIS LOOP IS HERE **<b>mov ebx, DWORD PTR [esp+40] mov eax, DWORD PTR [esp+44] mov DWORD PTR [esp+28], -1 mov edx, eax mov eax, 0 mov ecx, DWORD PTR [esp+28] mov edi, edx repnz scasb</b>** AS YOU CAN SEE it's done every time mov eax, ecx not eax sub eax, 1 cmp ebx, eax setb al test al, al jne .L3 mov eax, 0 .....
在Prætorian的答案详细阐述我build议如下:
for( auto i = strlen(s)-1; i > 0; --i ) {foo(s[i-1];}
-
auto
因为你不想关心strlen返回的types。 一个C ++ 11编译器(例如,gcc -std=c++0x
,不完全是C ++ 11,但是自动types工作)将为你做。 -
i = strlen(s)
因为你想比较0
(见下文) -
i > 0
因为与0比较(稍微)比任何其他数字都要快。
缺点是您必须使用i-1
才能访问string字符。