Will strlen be calculated multiple times if used in a loop condition?

后端 未结 18 1691
再見小時候
再見小時候 2020-12-07 15:10

I\'m not sure if the following code can cause redundant calculations, or is it compiler-specific?

for (int i = 0; i < strlen(ss); ++i)
{
    // blabla
}
<         


        
相关标签:
18条回答
  • 2020-12-07 16:04

    Arrgh, it will, even under ideal circumstances, dammit!

    As of today (January 2018), and gcc 7.3 and clang 5.0, if you compile:

    #include <string.h>
    
    void bar(char c);
    
    void foo(const char* __restrict__ ss) 
    {
        for (int i = 0; i < strlen(ss); ++i) 
        {
            bar(*ss);
        }
    }    
    

    So, we have:

    • ss is a constant pointer.
    • ss is marked __restrict__
    • The loop body cannot in any way touch the memory pointed to by ss (well, unless it violates the __restrict__).

    and still, both compilers execute strlen() every single iteration of that loop. Amazing.

    This also means the allusions/wishful thinking of @Praetorian and @JaredPar doesn't pan out.

    0 讨论(0)
  • 2020-12-07 16:05

    A good compiler may not calculate it every time, but I don't think you can be sure, that every compiler does it.

    In addition to that, the compiler has to know, that strlen(ss) does not change. This is only true if ss is not changed in for loop.

    For example, if you use a read-only function on ss in for loop but don't declare the ss-parameter as const, the compiler cannot even know that ss is not changed in the loop and has to calculate strlen(ss) in every iteration.

    0 讨论(0)
  • 2020-12-07 16:05

    If ss is of type const char * and you're not casting away the constness within the loop the compiler might only call strlen once, if optimizations are turned on. But this is certainly not behavior that can be counted upon.

    You should save the strlen result in a variable and use this variable in the loop. If you don't want to create an additional variable, depending on what you're doing, you may be ale to get away with reversing the loop to iterate backwards.

    for( auto i = strlen(s); i > 0; --i ) {
      // do whatever
      // remember value of s[strlen(s)] is the terminating NULL character
    }
    
    0 讨论(0)
  • 2020-12-07 16:08

    Formally yes, strlen() is expected to be called for every iteration.

    Anyway I do not want to negate the possibility of the existance of some clever compiler optimisation, that will optimise away any successive call to strlen() after the first one.

    0 讨论(0)
  • 2020-12-07 16:09

    well, I noticed that someone is saying that it is optimized by default by any "clever" modern compiler. By the way look at results without optimization. I tried:
    Minimal C code:

    #include <stdio.h>
    #include <string.h>
    
    int main()
    {
     char *s="aaaa";
    
     for (int i=0; i<strlen(s);i++)
      printf ("a");
     return 0;
    }
    

    My compiler: g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
    Command for generation of assembly code: 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
         .....
    
    0 讨论(0)
  • 2020-12-07 16:10

    Yes. strlen will be calculated everytime when i increases.

    If you didn't change ss with in the loop means it won't affect logic otherwise it will affect.

    It is safer to use following code.

    int length = strlen(ss);
    
    for ( int i = 0; i < length ; ++ i )
    {
     // blabla
    }
    
    0 讨论(0)
提交回复
热议问题