Take the 2-minute tour ×

I've been seeing these two parallel phrases since I started C weeks ago, need someone with the knowledge of the C compiler to tell me which leads to better code.


char s[]="aString",*sp=&s,c;


char s[]="aString",*sp=&s;

Alright, I understand that version2 involves some repeating differencing, so is version1 always better than version 2? if not , what are some typical exceptions?

share|improve this question
As other's have said, I wouldn't expect any difference in performance with modern compilers, but I would personally prefer to use a temp variable to make it very clear that I'm performing the same operation on the same character. –  Vaughn Cato Aug 5 '12 at 4:50
add comment

3 Answers

up vote 3 down vote accepted

I'd expect those to be exactly the same at any reasonable optimization level - did you try it?


I wanted to confirm, so I tried it. Here's my example program (I fixed your pointer mismatch errors, too):

void operation(char);

void f1(void)
    char s[]="aString",*sp=s,c;
    while(c=*sp++) {

void f2(void)
    char s[]="aString",*sp=s;
    for(;*sp;sp++) {

Compiled with clang at -O3 on my Mac, here's the object file:

(__TEXT,__text) section
0000000000000000    pushq   %rbp
0000000000000001    movq    %rsp,%rbp
0000000000000004    pushq   %rbx
0000000000000005    pushq   %rax
0000000000000006    movq    $0x00676e6972745361,%rax
0000000000000010    movq    %rax,0xf0(%rbp)
0000000000000014    movb    $0x61,%al
0000000000000016    leaq    0xf1(%rbp),%rbx
000000000000001a    nopw    _f1(%rax,%rax)
0000000000000020    movsbl  %al,%edi
0000000000000023    callq   _operation
0000000000000028    movb    (%rbx),%al
000000000000002a    incq    %rbx
000000000000002d    testb   %al,%al
000000000000002f    jne 0x00000020
0000000000000031    addq    $0x08,%rsp
0000000000000035    popq    %rbx
0000000000000036    popq    %rbp
0000000000000037    ret
0000000000000038    nopl    _f1(%rax,%rax)
0000000000000040    pushq   %rbp
0000000000000041    movq    %rsp,%rbp
0000000000000044    pushq   %rbx
0000000000000045    pushq   %rax
0000000000000046    movq    $0x00676e6972745361,%rax
0000000000000050    movq    %rax,0xf0(%rbp)
0000000000000054    movb    $0x61,%al
0000000000000056    leaq    0xf1(%rbp),%rbx
000000000000005a    nopw    _f1(%rax,%rax)
0000000000000060    movsbl  %al,%edi
0000000000000063    callq   _operation
0000000000000068    movb    (%rbx),%al
000000000000006a    incq    %rbx
000000000000006d    testb   %al,%al
000000000000006f    jne 0x00000060
0000000000000071    addq    $0x08,%rsp
0000000000000075    popq    %rbx
0000000000000076    popq    %rbp
0000000000000077    ret

As you can see, literally identical.

share|improve this answer
+1 Excellent, it's always good to have solid evidence. –  Greg Hewgill Aug 5 '12 at 5:02
@Carl Norum : I understand this should probably go into another question, but how do you go about viewing the assembly output of the compiler? –  EthOmus Aug 5 '12 at 5:13
@EthOmus, on a Mac, it's otool -tV example.o, on Linux it would be objdump -d example.o. Check out the otool(1) and objdump(1) man pages for more information. –  Carl Norum Aug 5 '12 at 5:15
An easier option is to have the compiler output the assembler directly. The gcc family of compilers (gcc, clang, icc, ...) do that if you give them -S instead of -c –  Jens Gustedt Aug 5 '12 at 7:06
add comment

These days, any good compiler will compile those loops pretty much exactly the same.

You may wish to use a temporary variable c if it's shorter to type or makes your code easier to read. But don't do stuff like this for some sort of imagined performance benefit.

share|improve this answer
add comment

Any optimizing compiler worth its salt will optimize them to the same assembly code. Unless you've measured this with a profiler and determined that it's a bottleneck, don't bother trying to prematurely optimize it.

There are certain situations where, if the value is accessed more than once, that the compiler won't be able to be sure that the underlying string isn't changing, in which case it will have to do the memory access more than once. In those cases, there'd be a very slight advantage to caching the character in a variable, but even then the advantage will be very minimal. Something like this:

for( ; *sp; sp++) {

In this case, the compiler might not know if some_function modifies the underlying string, so it will have to read *sp from memory twice to ensure correct behavior in all cases.

share|improve this answer
add comment

Your Answer


