7

次のプログラムを検討してください。

#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);
}

次のアセンブリが生成されます(コメントは自分で追加しました。私はアセンブリの完全な初心者です)。

$ 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

ご覧のとおり、1 バイト、4 バイト、1 バイトの3 つのローカル変数 ( aiおよび) があります。bパディングを含めると、これは 12 バイトになります (コンパイラが 4 バイトに整列すると仮定)。

aコンパイラが変数の順序を ( 、b、 )に変更すると、メモリ効率が向上するのではないでしょうiか? その場合、必要なのは 8 バイトだけです。

ここで「グラフィック」表現:

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

                |
                v

+---+---+---+---+---+---+---+---+
| a | b |   |   | i             |
+---+---+---+---+---+---+---+---+
         ^^^^^^^
      2 bytes unused

コンパイラはこの最適化を行うことが許可されていますか (C 標準などによって)?

  • いいえの場合 (アセンブリの出力が示すように)、なぜですか?
  • はいの場合、なぜ上記のようにならないのですか?
4

5 に答える 5

4

コンパイラはこの最適化を行うことが許可されていますか (C 標準などによって)?

はい。

はいの場合、なぜ上記のようにならないのですか?

それは起こりました。

アセンブラーの出力を注意深く読んでください。

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

変数aはオフセット 26 にあります。 変数はbオフセット 27 にあります。 変数iはオフセット 28 にあります。

レイアウトを作成した画像を使用すると、次のようになります。

+---+---+---+---+---+---+---+---+
|   |   | a | b | i             |
+---+---+---+---+---+---+---+---+
 ^^^^^^^
 2 bytes unused
于 2013-04-09T12:10:07.273 に答える
2

コンパイラが変数の順序を変更すると、メモリ効率が向上しますか?

特定の CPU、特定の OS、および特定のコンパイラについて語らずして語ることはできません。一般に、コンパイラは最適に動作します。有意義な方法でコードを最適化するには、特定のシステムに関する深い知識が必要です。

あなたの場合、この場合、コンパイラは速度を最適化するように設定されている可能性があります。コンパイラは、すべての変数のアラインされたアドレスが最も効率的なコードを提供すると判断したようです。一部のシステムでは、より高速であるだけでなく、偶数アドレスに割り当てることが必須でもあります。これは、一部の CPU が整列アクセスしか処理できないためです。

コンパイラはこの最適化を行うことができますか (C 標準などによって)?

はい、C 標準では、変数を割り当てる必要さえありません。コンパイラは、これを任意の方法で完全に自由に処理でき、方法や理由を文書化する必要はありません。変数をどこにでも割り当てることができ、それらを完全に最適化するか、CPU レジスタ内、スタック、または机の下の小さな木製の箱に割り当てることができます。

于 2013-04-09T11:43:28.200 に答える