1. 程式人生 > >C語言字元陣列的初始化研究

C語言字元陣列的初始化研究

有一天一個朋友問了我一個很有意思的問題。他問我如果用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,
生成test.s檔案,內容如下,去掉了一些無關緊要的部分:
	.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
結果出乎我的意料,第16-19行彙編程式碼清楚的告訴我們,該編譯器是在常量儲存區(.rodata)裡面先生成一個"hello world"的字串,然後再初始化str陣列時分兩次將該字串拷貝到堆疊中。

那麼所有編譯器都是這樣做的嗎?因為通過立即數定址的方式也是可以對字串進行初始化的,問題有沒有編譯器是這樣做的呢?下面是我在另外一臺機器上執行的結果,原始碼用的還是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
從上面兩個列子可以看出採用什麼方式初始化字串是根據編譯器的不同而不同的,可以通過立即數定址的方式實現,也可以通過基址定址的方式實現。