我不确定以下代码是否会导致冗余计算,或者它是否特定于编译器?
for (int i = 0; i < strlen(ss); ++i)
{
    // blabla
}strlen()每次i增加时都会计算?
ss对循环内部执行的操作。
                ss永远不会被修改,则它可以将计算提升到循环之外。
                我不确定以下代码是否会导致冗余计算,或者它是否特定于编译器?
for (int i = 0; i < strlen(ss); ++i)
{
    // blabla
}strlen()每次i增加时都会计算?
ss对循环内部执行的操作。
                ss永远不会被修改,则它可以将计算提升到循环之外。
                Answers:
是, strlen()将在每次迭代中进行评估。在理想情况下,优化器有可能推断出价值不会改变,但我个人不会依靠这一点。
我会做类似的事情
for (int i = 0, n = strlen(ss); i < n; ++i)或可能
for (int i = 0; ss[i]; ++i)只要字符串在迭代过程中不会改变长度。如果可能,那么您将需要strlen()每次调用,或者通过更复杂的逻辑进行处理。
strlen无论如何都要执行的循环。
                    是的,每次使用循环时。然后它将每次计算字符串的长度。所以像这样使用它:
char str[30];
for ( int i = 0; str[i] != '\0'; i++)
{
//Something;
}在上面的代码中,str[i]仅验证位置字符串中的一个特定字符i每次循环开始一个循环时,,因此它将占用较少的内存并且效率更高。
有关更多信息,请参见此链接。
在下面的代码中,每次循环运行strlen都将计算整个字符串的长度,这将降低效率,花费更多时间并占用更多内存。
char str[];
for ( int i = 0; i < strlen(str); i++)
{
//Something;
}strlen,如果运行得太紧,您可能还应该考虑取消其他一些函数调用……
                    int strlen(char *s) { int len = 0; while(s[len] != '\0') len++; return len; }您在答案中的代码中所做的事情。我不是在争论一次而不是两次遍历字符串会节省更多时间,但是我看不到一个或另一个使用更多或更少的内存。还是您指的是用于保存字符串长度的变量?
                    一个好的编译器可能不会每次都计算它,但我认为您不能确定每个编译器都可以计算它。
除此之外,编译器必须知道,这strlen(ss)不会改变。仅当ss未for循环更改时才如此。
例如,如果ss在for循环中使用只读函数,但未将ss-parameter 声明为const,则编译器甚至无法知道ss循环中未更改该参数,因此必须strlen(ss)在每次迭代中进行计算。
ss不能在for循环中更改;不能从循环中调用的任何函数访问和更改它(要么因为它作为参数传递,要么因为它是全局变量或文件作用域变量)。常量资格也可能是一个因素。
                    restrict就是C99中要做的事情之一。
                    ss在for循环中调用了一个只读函数,那么即使声明const char*了其参数,编译器仍然需要重新计算长度,除非(a)知道ss指向const对象, (b)可以内联该函数,否则可以看到它是只读的。接受const char*参数并不保证不会修改所指向的数据,因为只要char*修改后的对象不是const并且不是字符串文字,就可以强制转换并进行修改。
                    如果ss是类型,const char *并且您没有放弃const循环内的本质,则编译器可能只会调用strlen,那么如果打开了优化功能,一次。但这当然不是可以指望的行为。
您应该将strlen结果保存在变量中,然后在循环中使用此变量。如果您不想创建其他变量,具体取决于您正在执行的操作,则可能不希望通过反转循环来向后迭代。
for( auto i = strlen(s); i > 0; --i ) {
  // do whatever
  // remember value of s[strlen(s)] is the terminating NULL character
}strlen完全是错误的。循环播放直到结束。
                    i > 0?那不应该i >= 0在这里吗?就我个人而言,strlen(s) - 1如果从字符串上向后迭代,那么终止也\0无需特别考虑。
                    i >= 0仅在您初始化为时才起作用strlen(s) - 1,但是如果您有一个长度为零的字符串,则初始值会下溢
                    i > 0在初始循环进入时对表达式求值?如果不是这样,那么您是对的,零长度的情况肯定会打破循环。如果是的话,您“简单地”得到一个有符号的i== -1 <0,因此如果条件为,则没有循环项i >= 0。
                    strlen的返回类型是无符号的,因此(strlen(s)-1) >= 0对于零长度字符串,其求值为true。
                    整个谓词代码将在for循环的每次迭代中执行。为了strlen(ss)记住调用结果,编译器至少需要知道
strlen无副作用ss在循环期间不会更改编译器不知道这些事情,因此无法安全地记住第一次调用的结果
ss为a size_t或将其分配到多个byte值中。然后,我弯曲的线程可以只将字节写入该地址,并且编译器将具有理解与之相关的方式ss。
                    int a = 0; do_something(); printf("%d",a);无法优化,do_something()可能会导致您执行未初始化的int事情,或者可能会爬回堆栈并a故意修改。实际上,gcc 4.5确实do_something(); printf("%d",0);使用-O3 对其进行了优化
                    是的。我增加时都会计算strlen。
如果您没有在循环中更改ss with ,则它不会影响逻辑,否则会影响逻辑。
使用以下代码更安全。
int length = strlen(ss);
for ( int i = 0; i < length ; ++ i )
{
 // blabla
}是的,strlen(ss)它将在每次迭代时计算长度。如果您ss通过某种方式增加,同时也增加i;会有无限循环。
截至今天(2018年1月)以及gcc 7.3和clang 5.0,如果您进行以下编译:
#include <string.h>
void bar(char c);
void foo(const char* __restrict__ ss) 
{
    for (int i = 0; i < strlen(ss); ++i) 
    {
        bar(*ss);
    }
}    因此,我们有:
ss 是一个常量指针。ss 被标记 __restrict__ss(嗯,除非违反__restrict__)。并且还,两种编译器执行strlen() 该循环的每一个迭代。惊人。
这也意味着@Praetorian和@JaredPar的典故/如意算盘不会成功。
是。
strlen() 每次计算 i增加且未优化。
下面的代码显示了为什么编译器不应该优化strlen()。
for ( int i = 0; i < strlen(ss); ++i )
{
   // Change ss string.
   ss[i] = 'a'; // Compiler should not optimize strlen().
}strlen。
                    好吧,我注意到有人说默认情况下,任何“聪明”的现代编译器都会对其进行优化。顺便看看没有优化的结果。我试过:
最小的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
     .....restrict-qualified。尽管在某些情况下,这种优化是合理的,但如果不restrict采取任何合理措施,可靠地识别此类情况所需的工作几乎肯定会超过收益。const restrict但是,如果字符串的地址具有限定符,则足以证明优化是合理的,而不必考虑其他任何条件。