tags:

views:

137

answers:

4

Suppose we have to use in some function deeply nested pointer very extensively:

function (ptr_a_t ptr_a) {
    ...
    a = ptr_a->ptr_b->ptr_c->val;
    b = ptr_a->ptr_b->ptr_c->val;
    ...
}

Assuming all pointers are checked and valid, is there performance degradation, problems with atomicity or other caveats (except readability) in comparison with:

function (ptr_a_t ptr_a) {
    val = ptr_a->ptr_b->ptr_c->val;
    ...
    a = val;
    b = val;
    ...
}

Update I compiled this c file (written only for investigation purposes) with gcc -S:

typedef struct {
  int val;
} c_str_t;

typedef struct {
  c_str_t *p_c;     
} b_str_t;

typedef struct {
  b_str_t *p_b;     
} a_str_t;

void func (a_str_t *p_a) 
{
     int a,b;

     a = p_a->p_b->p_c->val;
     b = p_a->p_b->p_c->val;

     printf("", a,b);
}

For gcc -S:

movl    8(%ebp), %eax
movl    (%eax), %eax
movl    (%eax), %eax
movl    (%eax), %eax
movl    %eax, -4(%ebp)
movl    8(%ebp), %eax
movl    (%eax), %eax
movl    (%eax), %eax
movl    (%eax), %eax
movl    %eax, -8(%ebp) 

For gcc -S -O1:

movl    8(%ebp), %eax
movl    (%eax), %eax
movl    (%eax), %eax
movl    (%eax), %eax
movl    %eax, 8(%esp)
movl    %eax, 4(%esp) 

The same I observe using volatile specificator inside structures. So, nested pointers are forcedly optimized.

+2  A: 

I'm pretty sure your compiler will optimize the two to the same code as gcc does.

You can check this very easily by generating the assembler code for both (in gcc use the -S switch) and compare them.

Remo.D
+3  A: 

Unless some of those intermediate struct members are marked volatile, the compiler should treat your two examples as equivalent. I would prefer your second code sample just because it looks cleaner.

Karmastan
Note that it says *should* treat them as equivalent. There is no rule that says this must or must not happen, it is dependent on the particular compiler (and possibly on the optimization options used).
bta
How optimizer can now whether one of the pointers is not changed (due to scheduler) between two lines in the first case?.
Pmod
@Pmod: unless something is marked "volatile", the compiler can assume that a variable doesn't spontaeously change in the middle of a function.
Karmastan
If your program uses shared-memory concurrency and, say, "ptr_b" can change between program statements, the program has a non-deterministic bug in it.
Karmastan
this also gets into locking, if you do your locking correctly the result is the same (in particular if you need to lock the top level struct the compiler will not move dereferences to before the lock) this is part of the whole 'correctly locked programs are sequentially consistent' thing
Spudd86
+2  A: 

Whether these will be treated as the same is implementation-dependent. Compile your code both ways and examine the assembly output to see how your compiler treats both cases.

On an embedded system I am developing for, I added an "intermediate" pointer like you did and saw an appreciable speed-up in the execution time of the function. In my case, the compiler was re-calculating the pointer chain from scratch each time and was not optimizing them down. Your compiler may be different, the only real way to tell is to try it both ways and measure the execution time.

bta
You're right. Without optimization, gcc recalculates pointers. See my update.
Pmod
A: 

The second code, takes more memory. it also has 3 memory copies while the first code has 2 memory copies. On the other hand the second code has more lookups than the first code, but it has less importance. Please notice your compiler may optimize the codes. So if we ignore ... statement, both codes will be translated to the same binary code.

Ehsan
Even a fairly simple optimization will probably take out the extra copy...unless val is used elsewhere in which case the copy is *not* extra.. In short, a decent compiler should manage both code scraps perfectly well.
dmckee