C编译器是否用一个成员优化结构?

时间:2013-11-10 07:41:57

标签: c struct

执行此操作时编译器会执行什么操作?

struct something {
    int number;
}

内存与int有什么不同?

4 个答案:

答案 0 :(得分:7)

  

C编译器是否使用单个成员优化结构?

这完全取决于编译器。和当前的编译器设置。并且编译的代码。和平台。以及天狼星和月亮的相对位置。我们不知道。如果您询问特定体系结构上的特定编译器,并且打开了特定的编译器标志,那么在编译给定的代码时,我们可以编译它并查看生成的程序集以查看它的作用。但是,你也可以为自己做这件事。


这就是说,一般来说,我希望现代优化编译器能够在开启相当高的优化级别时进行此转换。

编辑:关于可能存在什么样的差异:我不仅仅是谈论结构内部成员的偏移;正如其他人已经正确观察到的那样,访问此类结构的成员以及在独立int上操作时,很可能会生成完全相同的机器代码。

然而,还有其他与结构相关的属性可能会有所不同。我可以想到两个例子。

第一个与作业有关。当您分配给struct时,某些编译器将发出对memcpy()函数的调用,而对int的赋值可能只需要一条机器指令而无需任何函数调用,例如mov [address], [value]

第二个行为差异与函数返回值有关。一些(旧的)ABI规定返回struct的函数将它们的返回值推送到堆栈上,而简单的原始返回值(通常是内置的核心语言类型)通常被放入寄存器中。因此,对于非优化编译器,理论上可以生成push指令,将单个int放在堆栈上,而不是使用返回值寄存器。

答案 1 :(得分:3)

“优化”是什么意思?或者,更具体地说,在这种情况下,“非优化”机器代码会是什么样的?

使用包含单个int的结构的机器语义与独立int变量的机器语义相同。这意味着无论编译器是否进行任何优化,机器代码通常都是相同的。即这种结构本身就与独立的int变量相同。

换句话说,我不明白在这种情况下你会看到什么是“非优化”代码。 “非优化”的自由在哪里呢?

一个“非优化”机会可能是结构大小对齐,由于某些模糊的原因,最终可能会大于独立int的大小。但如果没有明确要求,这通常不会在实践中发生。

我还可以想象一个编译器会不断尝试将0添加到结构的起始地址以获取唯一字段的地址。但我从来没有见过编译器会在实践中做那样的事情。

答案 2 :(得分:2)

回答你的新问题:

  

内存与int有什么不同?

在实践中,答案是否定的。 允许实现对结构施加比在普通int上更高的对齐要求,从而扩展结构的 size 以匹配对准。但是,这样做没有用处,我也不知道有任何编译器。 (当然,所有主要cpu架构和操作系统的标准ABI都不允许这样做。)

至于其他方面:

  • 编译器为结构类型的赋值生成效率较低的代码是可能的,但不太可能。正如提到的H2CO3,它可能总是为结构赋值生成memcpy的调用,即使单字加载/存储也可以。

  • 无人接触的一个方面是调用约定中的参数传递和返回值。编写接受或返回结构类型作为参数或返回值的函数是罕见的(并且通常不赞成);通常,使用指针代替。但是在C中是允许的,并且传递或返回包含单个int的结构的调用约定是否与类型int的对象的约定匹配,或者使用一些其他机制来推广到更大的结构,是架构/ ABI特定的。

答案 3 :(得分:2)

虽然问题假设一个包含单个int的结构,但包含单个浮点变量的结构更有趣。许多处理器都有一个浮点单元(FPU),它与CPU的其余部分有些隔离。通常,主CPU将能够从/向内存加载和存储其寄存器,FPU也可以与其寄存器一起加载和存储,但主CPU的寄存器和FPU的寄存器之间没有直接路径。

通常,在调用函数时,在寄存器中传递参数和函数返回值比使调用者将它们存储在内存中并使被调用函数读出它们更快。但是,使用主CPU寄存器传递浮点参数和返回值只是最糟糕的机制:如double foo(double x) {return x*2.0}之类的例程;被调用y=foo(w+1.0)+3.0;,系统必须将w加载到FPU寄存器中,添加1.0,将其存储到内存中,将其加载到CPU寄存器中并调用foo然后必须将其存储到内存中,以便将其加载到FPU中。然后它将乘以2.0,将其存储回内存,将其加载到CPU寄存器中,然后返回,因此主代码可以将其存储到内存中,将其加载到FPU中,添加3.0,然后最终将其存储到Y.讨厌。

如果使用FPU寄存器传递浮点参数,性能会更好。但是,通常只能使用浮点基元类型。包含单个浮点变量的结构将在我知道使用主CPU寄存器或内存传递的每个系统上。在调用者和/或被调用的代码必须对值执行浮点数学运算的情况下,这可能是一件坏事,但在极少数情况下,它可能是一件好事,特别是如果主CPU必须做某事有问题的价值。例如,通过将值加载到主CPU寄存器并使其执行比较和交换,可以使用4字节浮点执行比较和交换操作,但是比较和交换例程在FPU寄存器中取一个值会比在内存或主CPU寄存器中取一个参数的值慢一些。我不知道性能优势足以证明使用结构是合理的,但了解它们可能会很好。