I have this code (my strlen function)
size_t slen(const char *str)
{
size_t len = 0;
while (*str)
{
len++;
str++;
}
return len;
}
Doing while (*str++)
, as shown below, the program execution time is much larger:
while (*str++)
{
len++;
}
I'm doing this to probe the code
int main()
{
double i = 11002110;
const char str[] = "long string here blablablablablablablabla"
while (i--)
slen(str);
return 0;
}
In first case the execution time is around 6.7 seconds, while in the second (using *str++
), the time is around 10 seconds!
Why so much difference?
What is the difference between char and char*? char[] is a character array whereas char* is a pointer reference. char[] is a specific section of memory in which we can do things like indexing, whereas char* is the pointer that points to the memory location.
*str takes value from address of str ; c = *str assigns this value to c ; (c = *str) != 0 checks if this value is not NULL . NULL is the end of string marker in C/C++, see "null terminated string" en.wikipedia.org/wiki/Null-terminated_string.
The expression str++ yields the value before incrementing its operand. So you are calling the function with the same value of str. From the C Standard (6.5.2.4 Postfix increment and decrement operators)
The str() function converts values to a string form so they can be combined with other strings.
Probably because the post-increment operator (used in the condition of the while
statement) involves keeping a temporary copy of the variable with its old value.
What while (*str++)
really means is:
while (tmp = *str, ++str, tmp)
...
By contrast, when you write str++;
as a single statement in the body of the while loop, it is in a void context, hence the old value isn't fetched because it's not needed.
To summarise, in the *str++
case you have an assignment, 2 increments, and a jump in each iteration of the loop. In the other case you only have 2 increments and a jump.
Trying this out on ideone.com, I get about 0.5s execution with *str++ here. Without, it takes just over a second (here). Using *str++ was faster. Perhaps with optimisation on *str++ can be done more efficiently.
This depends on your compiler, compiler flags, and your architecture. With Apple's LLVM gcc 4.2.1, I don't get a noticeable change in performance between the two versions, and there really shouldn't be. A good compiler would turn the *str
version into something like
IA-32 (AT&T Syntax):
slen:
pushl %ebp # Save old frame pointer
movl %esp, %ebp # Initialize new frame pointer
movl -4(%ebp), %ecx # Load str into %ecx
xor %eax, %eax # Zero out %eax to hold len
loop:
cmpb (%ecx), $0 # Compare *str to 0
je done # If *str is NUL, finish
incl %eax # len++
incl %ecx # str++
j loop # Goto next iteration
done:
popl %ebp # Restore old frame pointer
ret # Return
The *str++
version could be compiled exactly the same (since changes to str
aren't visible outside slen
, when the increment actually occurs isn't important), or the body of the loop could be:
loop:
incl %ecx # str++
cmpb -1(%ecx), $0 # Compare *str to 0
je done # If *str is NUL, finish
incl %eax # len++
j loop # Goto next iteration
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With