8

单个成员是否struct具有与成员类型相同的性能(内存使用和速度)?

示例

这段代码只有一个struct成员:

struct my_int
{
    int value;
};

的性能是my_int一样的int吗?

4

4 回答 4

6

总体同意@harper,但要注意以下几点:

“非结构化”数组和结构中的数组有一个典型的区别。

char s1[1000];
// vs
typedef struct {
  char s2[1000];
} s_T;
s_T s3;

调用函数时...

void f1(char s[1000]);
void f2(s_T s);
void f3(s_T *s);

// Significant performance difference is not expected.
// In both, only an address is passed.
f1(s1);
f1(s3.s2);

// Significant performance difference is expected.
// In the second case, a copy of the entire structure is passed.
// This style of parameter passing is usually frowned upon.
f1(s1);
f2(s3);

// Significant performance difference is not expected.
// In both, only an address is passed.
f1(s1);
f3(&s3);
于 2013-11-09T18:50:46.157 回答
4

在某些情况下,ABI 可能具有返回结构并将它们传递给函数的特定规则。例如,给定

struct S { int m; };
struct S f(int a, struct S b);
int g(int a, S b);

例如,调用f或可能传入一个寄存器,然后传入堆栈。类似地,调用可以使用寄存器作为返回值,而调用可能需要调用者设置一个存储其结果的位置。gabgff

这种性能差异通常可以忽略不计,但可能产生显着差异的一种情况是这种差异启用或禁用尾递归。

假设g实现为int g(int a, struct S b) { return g(a, b).m; }。现在,在f's 结果以与 's 相同的方式返回的实现上g,这可能会编译为(clang 的实际输出)

        .文件“test.c”
        。文本
        .globl g
        .align 16, 0x90
        .type g,@函数
克:#@g
        .cfi_startproc
#BB#0:
        jmp f # 尾部调用
.ltmp0:
        .size g, .Ltmp0-g
        .cfi_endproc


        .section ".note.GNU-stack","",@progbits

但是,在其他实现中,这样的尾调用是不可能的,因此如果您想为深度递归函数实现相同的结果,您确实需要提供f相同g的返回类型,否则您将面临堆栈溢出的风险。(我知道尾调用不是强制性的。)

不过,这并不意味着int比 快S,也不意味着S比 快int。无论是否使用,内存使用都是相似的intS只要始终使用相同的内存即可。

于 2014-02-08T10:37:00.863 回答
3

如果编译器对使用结构而不是单个变量有任何惩罚,则严格取决于编译器和编译器选项。

但是当你的结构只包含一个成员时,编译器没有理由做出任何改变。应该有额外的代码来访问该成员或取消引用任何指向此类结构的指针。如果您没有这种过度简化的结构和一个成员延迟,则可能会花费一条额外的 CPU 指令,具体取决于使用的 CPU。

于 2013-11-09T15:51:11.550 回答
0

带有 GCC 10.2.0 -O3 的最小示例给出完全相同的输出,即没有结构引入的开销:

diff -u0 <(

gcc -S -o /dev/stdout -x c -std=gnu17 -O3 -Wall -Wextra - <<EOF
// Out of the box
void OOTB(int *n){
  *n+=999;
}
EOF

) <(

gcc -S -o /dev/stdout -x c -std=gnu17 -O3 -Wall -Wextra - <<EOF
// One member struct
typedef struct { int inq_n; } inq;
void OMST(inq *n){
  n->inq_n+=999;
}
EOF

)
--- /dev/fd/63  [...]
+++ /dev/fd/62  [...]
@@ -4,3 +4,3 @@
-   .globl  OOTB
-   .type   OOTB, @function
-OOTB:
+   .globl  OMST
+   .type   OMST, @function
+OMST:
@@ -13 +13 @@
-   .size   OOTB, .-OOTB
+   .size   OMST, .-OMST

不确定更现实/复杂的情况。

于 2021-01-28T03:08:47.330 回答