コンパイラは、文字列のインスタンスを 1 つ格納できるほどスマートでなければなりません。これは、プログラムのアセンブリ出力をチェックすることで確認できます。
たとえば、GCC を使用すると、次のようになります。
最初の例が「global.c」と呼ばれているとします。
gcc -Wall -S global.c
.file "global.c"
.globl OUTPUT
.data
.align 16
.type OUTPUT, @object
.size OUTPUT, 20
OUTPUT:
.string "Hello, world!!!"
.zero 4
.section .rodata
.LC0:
.string "%s is %d characters long.\n"
.text
.globl main
.type main, @function
main:
// More code...
プリプロセッサの例が「preproc.c」と呼ばれているとします。
gcc -Wall -S preproc.c
.file "preproc.c"
.section .rodata
.LC0:
.string "%s is %d characters long.\n"
.LC1:
.string "Hello, world!!!"
.text
.globl main
.type main, @function
main:
// More code...
どちらの場合も、「Hello, world!!!」のコピーは 1 つだけです。および「%s は %d 文字の長さです。\n」が存在します。最初の例では、コードに変更可能な配列があるため、20 文字分のスペースを節約する必要があります。これを変更した場合
char OUTPUT[20] = "Hello, world!!!";
に
const char * const OUTPUT = "Hello, world!!!";
あなたは得るでしょう:
.file "global.c"
.globl OUTPUT
.section .rodata
.LC0:
.string "Hello, world!!!"
.align 8
.type OUTPUT, @object
.size OUTPUT, 8
OUTPUT:
.quad .LC0
.LC1:
.string "%s is %d characters long.\n"
.text
.globl main
.type main, @function
main:
// More code...
これで、ポインターと文字列のためだけにスペースを節約できます。
この状況ではどちらが良いかは無視できますが、文字列のスコープがメイン関数内にとどまるようにプリプロセッサを使用することをお勧めします。
どちらも最適化されたほぼ同じコードを出力します。
( ) を含む Global.c const char * const OUTPUT
:
gcc -Wall -O3 -S global.c
.file "global.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "Hello, world!!!"
.LC1:
.string "%s is %d characters long.\n"
.section .text.startup,"ax",@progbits
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB44:
.cfi_startproc
subq $8, %rsp
.cfi_def_cfa_offset 16
movl $15, %ecx
movl $.LC0, %edx
movl $.LC1, %esi
movl $1, %edi
xorl %eax, %eax
call __printf_chk
xorl %eax, %eax
addq $8, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE44:
.size main, .-main
.globl OUTPUT
.section .rodata
.align 8
.type OUTPUT, @object
.size OUTPUT, 8
OUTPUT:
.quad .LC0
.ident "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section .note.GNU-stack,"",@progbits
Preproc.c
gcc -Wall -O3 -S preproc.c
.file "preproc.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "Hello, world!!!"
.LC1:
.string "%s is %d characters long.\n"
.section .text.startup,"ax",@progbits
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB44:
.cfi_startproc
subq $8, %rsp
.cfi_def_cfa_offset 16
movl $15, %ecx
movl $.LC0, %edx
movl $.LC1, %esi
movl $1, %edi
xorl %eax, %eax
call __printf_chk
xorl %eax, %eax
addq $8, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE44:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section .note.GNU-stack,"",@progbits
両方のmain
関数を見ると、命令が同じであることがわかります。