增加结构体成员

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 的方式是否做了相同的事情?顺带一提,是不是前置递增比后置递增更高效?

谢谢!

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

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()。

就性能而言,我希望后自增更加高效,因为内存位置被访问的次数较少。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接