C語言字元陣列的初始化研究
阿新 • • 發佈:2019-02-15
有一天一個朋友問了我一個很有意思的問題。他問我如果用C程式碼在一個函式裡面寫一行字串初始化程式碼,如“char str[]="hello world",那麼該字串是如何被初始化的呢?
開始我不以為然,立刻回答:該字串應該是程式在執行時,通過立即數定址直接寫入堆疊中的嘛。結果該朋友反問了一句:真的嗎?我隱約覺得不對勁,等回來我寫了段程式碼看看它到底是怎麼初始化的。
程式碼(test.c)如下:
int main(int argc, char *argv[]){
char str[]="hello world";
str[1]='a';
return 0;
}
然後gcc -S test.c,結果出乎我的意料,第16-19行彙編程式碼清楚的告訴我們,該編譯器是在常量儲存區(.rodata)裡面先生成一個"hello world"的字串,然後再初始化str陣列時分兩次將該字串拷貝到堆疊中。.file "test.c" .section .rodata .LC0: .string "hello world" .text .globl main .type main, @function main: .LFB2: pushq %rbp .LCFI0: movq %rsp, %rbp .LCFI1: movl %edi, -20(%rbp) movq %rsi, -32(%rbp) movq .LC0(%rip), %rax movq %rax, -16(%rbp) movl .LC0+8(%rip), %eax movl %eax, -8(%rbp) movb $97, -15(%rbp) movl $0, %eax leave ret .LEFDE1: .ident "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-44)" .section .note.GNU-stack,"",@progbits
那麼所有編譯器都是這樣做的嗎?因為通過立即數定址的方式也是可以對字串進行初始化的,問題有沒有編譯器是這樣做的呢?下面是我在另外一臺機器上執行的結果,原始碼用的還是test.c。
.file "test.c" .text .globl main .type main, @function main: .LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movl %edi, -20(%rbp) movq %rsi, -32(%rbp) movl $1819043176, -16(%rbp) movl $1870078063, -12(%rbp) movl $6581362, -8(%rbp) movb $97, -16(%rbp) movl $0, %eax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (GNU) 4.6.2 20111027 (Red Hat 4.6.2-1)" .section .note.GNU-stack,"",@progbits
第15-17行顯示,在4.6版本的GCC裡面是通過立即數定址來完成字串的初始化的。1819043176和1870078063表示的含義下面的表格解釋的很清楚,因為這臺測試的機器是小端機器,所以在讀字串的時候是從右往左讀的。
十進位制 | 十六進位制 | 對應ASCII字串 |
1819043176 | 6C6C6568 | lleh |
1870078063 | 6F77206F | ow o |
6581362 | 646C72 | dlr |