14

假设我有一个定义如下的结构

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做同样的事情吗?当我们这样做时,前置增量是否真的比后置增量更有效?

谢谢!

4

2 回答 2

10

前两个将具有相同的效果(当像这样单独在一行上时),但第三种方法不是有效的 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
于 2012-09-30T17:05:35.673 回答
3

如果您的唯一意图是增加 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()。

在性能方面,我希望后增量更有效,因为内存位置被触摸的次数更少。

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

于 2012-09-30T17:52:48.150 回答