我过去曾参与过嵌入式系统的项目,我们已经重新安排了堆栈变量声明的顺序,以减少生成的可执行文件的大小。例如,如果我们有:

void func()
{
    char c;
    int i;
    short s;
    ...
}

我们会将此重新排序为:

void func()
{
    int i;
    short s;
    char c;
    ...
}

由于对齐问题,第一个导致使用12个字节的堆栈空间,第二个导致只有8个字节。

这是C编译器的标准行为还是我们使用的编译器的缺点?

在我看来,如果需要,编译器应该能够重新排序堆栈变量以支持更小的可执行文件大小。有人向我建议,C标准的某些方面可以防止这种情况,但无论如何我都无法找到有信誉的来源。

作为奖励问题,这是否也适用于C ++编译器?

修改

如果答案是肯定的,那么C / C ++编译器可以重新排列堆栈变量,你能给出一个肯定会这样做的编译器的例子吗?我希望看到编译器文档或类似的东西支持这一点。

再次编辑

感谢大家的帮助。对于文档,我能找到的最好的东西是论文

这里讨论的项目是使用ADS编译器进行ARM开发。在该编译器的文档中提到,像我所示的排序声明可以提高性能以及堆栈大小,因为ARM-Thumb架构如何计算本地堆栈帧中的地址。该编译器没有自动重新排列本地人以利用这一点。这里链接的文章说,截至2003年,GCC也没有重新安排堆栈帧以改善ARM-Thumb处理器的参考局部性,但它暗示你可以。

我找不到任何明确说明在GCC中实施的内容,但我认为这篇论文可以证明你是正确的。再次感谢。

有帮助吗?

解决方案

由于标准中没有任何内容禁止C或C ++编译器,是的,编译器可以做到这一点。

对于必须保持相对顺序的聚合(即结构)是不同的,但编译器仍然可以插入填充字节以实现优选的对齐。

IIRC较新的MSVC编译器利用这种自由来对抗当地人的缓冲区溢出。

作为旁注,在C ++中,即使编译器重新排序内存布局,破坏的顺序也必须是声明的反向顺序。

(我不能引用章节和诗句,但这是来自记忆。)

其他提示

编译器不仅可以重新排序局部变量的堆栈布局,还可以将它们分配给寄存器,有时将它们分配到寄存器中,有时在堆栈中,它可以将两个本地分配给内存中的同一个插槽(如果他们的有效范围不重叠)甚至可以完全消除变量。

甚至不需要存在堆栈(实际上,C99标准没有单个“堆栈”出现)。所以是的,编译器可以自由地做任何想做的事情,只要保留具有自动存储持续时间的变量的语义。

至于一个例子:我遇到过多次无法在调试器中显示局部变量的情况,因为它存储在寄存器中。

编译器甚至可以自由地从堆栈中删除变量,只有在分析显示变量的地址永远不被采用/使用时才能进行注册。

编译器甚至可能根本不使用堆栈来处理数据。如果你在一个如此小的平台上,你担心8比12的字节堆栈,那么很可能会有编译器具有非常专业的方法。 (一些PIC和8051编译器会浮现在脑海中)

你在为什么处理器编译?

德州仪器62xx系列DSP的编译器能够做到 “整个程序优化”。 (你可以把它关掉)

这是您的代码重新排列的地方,而不仅仅是本地人。因此,执行顺序最终并不像你期望的那样。

C和C ++实际上 承诺一个内存模型(在JVM的意义上说),所以事情可能完全不同而且仍然合法。

对于那些不了解它们的人,62xx系列每个时钟周期DSP有8个指令;在750Mhz时,它们以6e + 9指令达到峰值。反正有些时候。它们执行并行执行,但指令排序是在编译器中完成的,而不是CPU,如Intel x86。

PIC和Rabbit嵌入式主板不会拥有堆栈,除非你特别要求。

它是编译器细节,如果他想要那样,就可以制作他自己的反编译器。

如果可以的话,一个像样的编译器会将局部变量放在寄存器中。如果注册压力过大(空间不够)或者变量的地址被占用,变量只应放在堆栈上,这意味着它需要存在于内存中。

据我所知,没有任何内容可以说变量需要放在C / C ++的任何特定位置或堆栈上。编译器会将它们放在最适合性能的地方和/或任何方便编译器编写者的地方。

AFAIK C或C ++的定义中没有任何内容指定编译器应如何在堆栈上对本地变量进行排序。我会说依赖于编译器在这种情况下可能会做的事情是一个坏主意,因为编译器的下一个版本可能会采用不同的方式。如果您花费时间和精力来命令本地变量来保存几个字节的堆栈,那么这几个字节最好对系统的运行至关重要。

这不能回答你的问题,但这是关于相关问题的2美分......

我没有堆栈空间优化的问题但是我遇到了堆栈上双变量错误对齐的问题。可以从任何其他函数调用函数,并且堆栈指针值可以具有任何未对齐的值。所以我想出了下面的想法。这不是原始代码,我只是写了......

#pragma pack(push, 16)

typedef struct _S_speedy_struct{

 double fval[4];
 int64  lval[4];
 int32  ival[8];

}S_speedy_struct;

#pragma pack(pop)

int function(...)
{
  int i, t, rv;
  S_speedy_struct *ptr;
  char buff[112]; // sizeof(struct) + alignment

  // ugly , I know , but it works...
  t = (int)buff;
  t +=  15; // alignment - 1
  t &= -16; // alignment
  ptr = (S_speedy_struct *)t;

  // speedy code goes on...
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top