Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

incrementing struct members

Say I have a struct defined as follows

struct my_struct
{
     int num;
};

....

Here I have a pointer to my_struct and I want to do an increment on num

void foo(struct my_struct* my_ptr)
{
     // increment num
     // method #1
     my_ptr->num++;

     // method #2
     ++(my_ptr->num);

     // method #3
     my_ptr->++num;

}

Do these 3 ways of incrementing num do the same thing? While we're at it, is it true that pre-increment is more efficient than post-increment?

Thanks!

like image 727
user1508893 Avatar asked Sep 30 '12 17:09

user1508893


2 Answers

First two will have the same effect (when on a line on their own like that), but the third method isn't valid C code (you can't put the ++ there).

As for efficiency, there is no difference. The difference you may have heard people talking about is when, in C++, you increment a non-pointer data type, such as an iterator. In some cases, pre-increment can be faster there.

You can see the generated code using GCC Explorer.

void foo(struct my_struct* my_ptr)
{
    my_ptr->num++;
}

void bar(struct my_struct* my_ptr)
{
    ++(my_ptr->num);
}

Output:

foo(my_struct*):                      # @foo(my_struct*)
    incl    (%rdi)
    ret

bar(my_struct*):                      # @bar(my_struct*)
    incl    (%rdi)
    ret

As you can see, there's no difference whatsoever.

The only possible difference between the first two is when you use them in expressions:

my_ptr->num = 0;
int x = my_ptr->num++; // x = 0

my_ptr->num = 0;
int y = ++my_ptr->num; // y = 1
like image 68
Peter Alexander Avatar answered Oct 31 '22 05:10

Peter Alexander


If your only intention is to increment the value of num then the 1st and 2nd method will yield same intented result to the callee method.

However, if you change your code to the following, you can see the difference between the code generated by gcc (assembly level code):

struct my_struct
{
     int num;
};

void foo(struct my_struct* my_ptr)
{
        printf("\nPost Increment: %d", my_ptr->num++);
}

int main()
{
        struct my_struct a;
        a.num = 10;

        foo(&a);
}

Now compile it using: gcc -masm=intel -S structTest.c -o structTest.s This asks gcc to generate the assembly code:

Open structTest.s in a text editor.

foo:
.LFB0:
         push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        **mov     QWORD PTR [rbp-8], rdi**
        mov     rax, QWORD PTR [rbp-8]
        mov     eax, DWORD PTR [rax]
        mov     edx, eax
        **lea     ecx, [rax+1]**
        mov     rax, QWORD PTR [rbp-8]
        mov     DWORD PTR [rax], ecx
        mov     eax, OFFSET FLAT:.LC0
        mov     esi, edx
        mov     rdi, rax
        mov     eax, 0
        call    printf
        leave
        ret
        .cfi_endproc

main:
.LFB1:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        **mov     DWORD PTR [rbp-16], 10
        lea     rax, [rbp-16]
        mov     rdi, rax
        call    foo**
        leave
        ret
        .cfi_endproc

And when you change the operation to pre-increment, the follwoing code is generated:

foo:
.LFB0:
        .cfi_startproc
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        **mov     QWORD PTR [rbp-8], rdi**
        mov     rax, QWORD PTR [rbp-8]
        mov     eax, DWORD PTR [rax]
        **lea     edx, [rax+1]**
        mov     rax, QWORD PTR [rbp-8]
        **mov     DWORD PTR [rax], edx**
        mov     rax, QWORD PTR [rbp-8]
        **mov     edx, DWORD PTR [rax]**
        mov     eax, OFFSET FLAT:.LC0
        mov     esi, edx
        mov     rdi, rax
        mov     eax, 0
        call    printf
        leave
        ret
        .cfi_endproc

So, you would see that in the second case, the compiler increments the num value and passes on this num value to printf().

In terms of performance, I would expect the post-increment to be more efficient since the memory locations are touched a fewer number of times.

The important lines have been marked between ** in the above code.

like image 29
FunBoy Avatar answered Oct 31 '22 05:10

FunBoy