rya*_*n_s 15 c c++ compiler-construction callstack alignment
我曾经在嵌入式系统的项目上工作过,我们重新安排了堆栈变量声明的顺序,以减少生成的可执行文件的大小.例如,如果我们有:
void func()
{
char c;
int i;
short s;
...
}
Run Code Online (Sandbox Code Playgroud)
我们会将此重新排序为:
void func()
{
int i;
short s;
char c;
...
}
Run Code Online (Sandbox Code Playgroud)
由于对齐问题,第一个导致使用12个字节的堆栈空间,第二个导致仅8个字节.
这是C编译器的标准行为,还是我们使用的编译器的缺点?
在我看来,编译器应该能够重新排序堆栈变量,以便在需要时支持更小的可执行文件大小.有人向我建议,C标准的某些方面可以防止这种情况,但我无法以任何方式找到信誉良好的来源.
作为一个额外的问题,这也适用于C++编译器吗?
编辑
如果答案是肯定的,那么C/C++编译器可以重新排列堆栈变量,你能给出一个肯定会这样做的编译器的例子吗?我想看看编译器文档或类似的东西支持这一点.
再次编辑
谢谢大家的帮助.对于文档,我能够找到的最好的东西是GCC(pdf)中的最佳堆栈槽分配,由Naveen Sharma和Sanjiv Kumar Gupta撰写,于2003年在海湾合作委员会峰会会议上提交.
这里讨论的项目是使用ADS编译器进行ARM开发.在该编译器的文档中提到,像我所示的排序声明可以提高性能以及堆栈大小,因为ARM-Thumb架构如何计算本地堆栈帧中的地址.该编译器没有自动重新排列本地人以利用这一点.这里链接的论文说,截至2003年,GCC也没有重新安排堆栈帧以改善ARM-Thumb处理器的参考局部性,但它暗示你可以.
我找不到任何明确表示这在GCC中实施过的东西,但我认为这篇论文可以证明你是正确的.再次感谢.
Wal*_*ght 39
编译器不仅可以重新排序局部变量的堆栈布局,还可以将它们分配给寄存器,有时将它们分配到寄存器中,有时在堆栈中,它可以将两个本地分配给内存中的同一个插槽(如果它们的有效范围不重叠)它甚至可以完全消除变量.
pet*_*hen 22
由于标准中没有任何内容禁止C或C++编译器,是的,编译器可以做到这一点.
聚合(即结构)不同,其中必须保持相对顺序,但编译器仍可插入填充字节以实现优选的对齐.
IIRC较新的MSVC编译器利用这种自由来对抗当地人的缓冲区溢出.
作为旁注,在C++中,即使编译器重新排序内存布局,破坏的顺序也必须是声明的反向顺序.
(我不能引用章节和诗句,但这是来自记忆.)
zvr*_*rba 10
堆栈甚至不需要存在(实际上,C99标准没有单个"堆栈"出现).所以是的,编译器可以自由地做任何想做的事情,只要保留具有自动存储持续时间的变量的语义.
举个例子:我遇到过多次无法在调试器中显示局部变量的情况,因为它存储在寄存器中.
Texas Instruments 62xx 系列 DSP 的编译器能够执行“整个程序优化”。(你可以关闭它)
这是您的代码重新排列的地方,而不仅仅是当地人。因此,执行顺序最终并不完全符合您的预期。
C 和 C++实际上并没有承诺内存模型(就 JVM 而言),因此事情可能完全不同但仍然合法。
对于那些不了解它们的人,62xx 系列是每时钟周期 8 条指令的 DSP;在 750Mhz 时,它们在 6e+9 条指令处达到峰值。反正有些时候。它们执行并行执行,但指令排序是在编译器中完成的,而不是像 Intel x86 那样在 CPU 中完成。
PIC的兔嵌入式主板不具备,除非你要求特别好听栈。