递增struct成员

时间:2012-09-30 17:04:15

标签: c struct increment pre-increment

假设我的结构定义如下

struct my_struct
{
     int num;
};

...

在这里,我有一个指向my_struct的指针,我希望在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;

}

这三种递增num的方法是否做同样的事情? 虽然我们正处于这种状态,但预增量是否比后增量更有效?

谢谢!

2 个答案:

答案 0 :(得分:9)

前两个会产生相同的效果(当他们自己就像这样),但第三个方法是无效的C代码(你不能把++放在那里)。

就效率而言,没有区别。你可能听到人们谈论的差异是,在C ++中,你增加了非指针数据类型,例如迭代器。在某些情况下,预增量可能会更快。

您可以使用GCC Explorer查看生成的代码。

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

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

输出:

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

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

如你所见,没有任何区别。

前两个之间唯一可能的区别是当你在表达式中使用它们时:

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

my_ptr->num = 0;
int y = ++my_ptr->num; // y = 1

答案 1 :(得分:2)

如果你的唯一目的是增加num的值,那么第一个和第二个方法将产生与被调用者方法相同的意图结果。

但是,如果将代码更改为以下代码,则可以看到gcc生成的代码之间的差异(程序集级别代码):

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);
}

现在使用以下命令编译它:gcc -masm = intel -S structTest.c -o structTest.s 这要求gcc生成汇编代码:

在文本编辑器中打开structTest.s。

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

当您将操作更改为预增量时,将生成以下代码:

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

因此,您会看到在第二种情况下,编译器递增num值并将此num值传递给printf()。

就性能而言,我希望后增量更有效,因为内存位置的触摸次数更少。

在上面的代码中,重要的行标记在**之间。