是否允许编译器通过重新排序局部变量来优化堆栈内存使用?

Mar*_*ant 7 c stack alignment compiler-optimization

考虑以下程序:

#include <stdio.h>

void some_func(char*, int*, char*);

void stack_alignment(void) {
    char a = '-';
    int i = 1337;
    char b = '+';
    some_func(&a, &i, &b); // to prevent the compiler from removing the local variables
    printf("%c|%i|%c", a, i, b);
}
Run Code Online (Sandbox Code Playgroud)

它生成以下程序集(由我自己添加的注释,我是程序集的完整新手):

$ vim stack-alignment.c
$ gcc -c -S -O3 stack-alignment.c
$ cat stack-alignment.s
        .file   "stack-alignment.c"
        .section .rdata,"dr"
LC0:
        .ascii "%c|%i|%c\0"
        .text
        .p2align 2,,3
        .globl  _stack_alignment
        .def    _stack_alignment;       .scl    2;      .type   32;     .endef
_stack_alignment:
LFB7:
        .cfi_startproc
        subl    $44, %esp
        .cfi_def_cfa_offset 48
        movb    $45, 26(%esp)    // local variable 'a'
        movl    $1337, 28(%esp)  // local variable 'i'
        movb    $43, 27(%esp)    // local variable 'b'
        leal    27(%esp), %eax
        movl    %eax, 8(%esp)
        leal    28(%esp), %eax
        movl    %eax, 4(%esp)
        leal    26(%esp), %eax
        movl    %eax, (%esp)
        call    _some_func
        movsbl  27(%esp), %eax
        movl    %eax, 12(%esp)
        movl    28(%esp), %eax
        movl    %eax, 8(%esp)
        movsbl  26(%esp), %eax
        movl    %eax, 4(%esp)
        movl    $LC0, (%esp)
        call    _printf
        addl    $44, %esp
        .cfi_def_cfa_offset 4
        ret
        .cfi_endproc
LFE7:
        .def    _some_func;     .scl    2;      .type   32;     .endef
        .def    _printf;        .scl    2;      .type   32;     .endef
Run Code Online (Sandbox Code Playgroud)

如您所见,有3个局部变量(a,ib),大小为1字节,4字节和1字节.包括填充,这将是12字节(假设编译器对齐4个字节).

如果编译器将变量的顺序改为(,)a,那么它的内存效率会不会更高?那么只需要8个字节.bi

这里有一个"图形"表示:

    3 bytes unused                  3 bytes unused
     vvvvvvvvvvv                     vvvvvvvvvvv
+---+---+---+---+---+---+---+---+---+---+---+---+
| a |   |   |   | i             | b |   |   |   |
+---+---+---+---+---+---+---+---+---+---+---+---+

                |
                v

+---+---+---+---+---+---+---+---+
| a | b |   |   | i             |
+---+---+---+---+---+---+---+---+
         ^^^^^^^
      2 bytes unused
Run Code Online (Sandbox Code Playgroud)

是否允许编译器进行此优化(通过C标准等)?

  • 如果没有(我认为装配输出显示),为什么?
  • 如果是的话,为什么不在上面发生?

Dan*_*her 7

编译器可以根据需要自由布局局部变量.它甚至不需要使用堆栈.

如果它使用堆栈,它可以按照与堆栈上的声明顺序无关的顺序存储局部变量.

是否允许编译器进行此优化(通过C标准等)?

  • 如果是的话,为什么不在上面发生?

嗯,这是一个优化吗?

目前尚不清楚.它少了几个字节,但这很少重要.但是在某些体系结构中,char如果它以字对齐的方式存储,则读取它可能会更快.因此,将chars彼此相邻会迫使其中一个至少不进行单词对齐并使其读取速度变慢.


Art*_*Art 4

编译器是否允许进行此优化(根据 C 标准等)?

是的。

如果是的话,为什么上面的情况没有发生呢?

它确实发生了。

仔细阅读汇编器的输出。

    movb    $45, 26(%esp)    // local variable 'a'
    movl    $1337, 28(%esp)  // local variable 'i'
    movb    $43, 27(%esp)    // local variable 'b'
Run Code Online (Sandbox Code Playgroud)

变量a位于偏移量 26 处。变量b位于偏移量 27 处。变量i位于偏移量 28 处。

使用您制作的图像,布局现在是:

+---+---+---+---+---+---+---+---+
|   |   | a | b | i             |
+---+---+---+---+---+---+---+---+
 ^^^^^^^
 2 bytes unused
Run Code Online (Sandbox Code Playgroud)