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

C++CGccOptimizationStrlen

C++ Problem Overview


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
}

Will strlen() be calculated every time when i increases?

C++ Solutions


Solution 1 - C++

Yes, strlen() will be evaluated on each iteration. It's possible that, under ideal circumstances, the optimiser might be able to deduce that the value won't change, but I personally wouldn't rely on that.

I'd do something like

for (int i = 0, n = strlen(ss); i < n; ++i)

or possibly

for (int i = 0; ss[i]; ++i)

as long as the string isn't going to change length during the iteration. If it might, then you'll need to either call strlen() each time, or handle it through more complicated logic.

Solution 2 - C++

Yes, every time you use the loop. Then it will every time calculate the length of the string. so use it like this:

char str[30];
for ( int i = 0; str[i] != '\0'; i++)
{
//Something;
}

In the above code str[i] only verifies one particular character in the string at location i each time the loop starts a cycle, thus it will take less memory and is more efficient.

See this Link for more information.

In the code below every time the loop runs strlen will count the length of the whole string which is less efficient, takes more time and takes more memory.

char str[];
for ( int i = 0; i < strlen(str); i++)
{
//Something;
}

Solution 3 - C++

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.

Solution 4 - C++

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
}

Solution 5 - C++

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.

Solution 6 - C++

The predicate code in it's entirety will be executed on every iteration of the for loop. In order to memoize the result of the strlen(ss) call the compiler would need to know that at least

  1. The function strlen was side effect free
  2. The memory pointed to by ss doesn't change for the duration of the loop

The compiler doesn't know either of these things and hence can't safely memoize the result of the first call

Solution 7 - C++

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
}

Solution 8 - C++

Yes, strlen(ss) will be calculated every time the code runs.

Solution 9 - C++

Yes, the strlen(ss) will calculate the length at each iteration. If you are increasing the ss by some way and also increasing the i; there would be infinite loop.

Solution 10 - C++

Yes, the strlen() function is called every time the loop is evaluated.

If you want to improve the efficiency then always remember to save everything in local variables... It will take time but it's very useful ..

You can use code like below:

String str="ss";
int l = strlen(str);

for ( int i = 0; i < l ; i++ )
{
    // blablabla
}

Solution 11 - C++

Not common nowadays but 20 years ago on 16 bit platforms, I'd recommend this:

for ( char* p = str; *p; p++ ) { /* ... */ }

Even if your compiler isn't very smart in optimization, the above code can result in good assembly code yet.

Solution 12 - C++

Yes. The test doesn't know that ss doesn't get changed inside the loop. If you know that it won't change then I would write:

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

Solution 13 - C++

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.

Solution 14 - C++

YES, in simple words. And there is small no in rare condition in which compiler is wishing to, as an optimization step if it finds that there is no changes made in ss at all. But in safe condition you should think it as YES. There are some situation like in multithreaded and event driven program, it may get buggy if you consider it a NO. Play safe as it is not going to improve the program complexity too much.

Solution 15 - C++

Yes.

strlen() calculated everytime when i increases and does not optimized.

Below code shows why the compiler should not optimize strlen().

for ( int i = 0; i < strlen(ss); ++i )
{
   // Change ss string.
   ss[i] = 'a'; // Compiler should not optimize strlen().
}

Solution 16 - C++

We can easily test it :

char nums[] = "0123456789";
size_t end;
int i;
for( i=0, end=strlen(nums); i<strlen(nums); i++ ) {
    putchar( nums[i] );
    num[--end] = 0;
}

Loop condition evaluates after each repetition, before restarting the loop .

Also be careful about the type you use to handle length of strings . it should be size_t which has been defined as unsigned int in stdio. comparing and casting it to int might cause some serious vulnerability issue.

Solution 17 - C++

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
     .....

Solution 18 - C++

Elaborating on Prætorian's answer I recommend the following:

for( auto i = strlen(s)-1; i > 0; --i ) {foo(s[i-1];}
  • auto because you don't want to care about which type strlen returns. A C++11 compiler (e.g. gcc -std=c++0x, not completely C++11 but auto types work) will do that for you.
  • i = strlen(s) becuase you want to compare to 0 (see below)
  • i > 0 because comparison to 0 is (slightly) faster that comparison to any other number.

disadvantage is that you have to use i-1 in order to access the string characters.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondaisyView Question on Stackoverflow
Solution 1 - C++Mike SeymourView Answer on Stackoverflow
Solution 2 - C++codeDEXTERView Answer on Stackoverflow
Solution 3 - C++MischView Answer on Stackoverflow
Solution 4 - C++PraetorianView Answer on Stackoverflow
Solution 5 - C++alkView Answer on Stackoverflow
Solution 6 - C++JaredParView Answer on Stackoverflow
Solution 7 - C++Kalai Selvan RaviView Answer on Stackoverflow
Solution 8 - C++Hisham MuneerView Answer on Stackoverflow
Solution 9 - C++Kumar ShoravView Answer on Stackoverflow
Solution 10 - C++RajanView Answer on Stackoverflow
Solution 11 - C++LucianoView Answer on Stackoverflow
Solution 12 - C++DanSView Answer on Stackoverflow
Solution 13 - C++einpoklumView Answer on Stackoverflow
Solution 14 - C++Pervez AlamView Answer on Stackoverflow
Solution 15 - C++Amir SaniyanView Answer on Stackoverflow
Solution 16 - C++RshView Answer on Stackoverflow
Solution 17 - C++TebeView Answer on Stackoverflow
Solution 18 - C++steffenView Answer on Stackoverflow