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
從上面兩個列子可以看出採用什麼方式初始化字符串是根據編譯器的不同而不同的,可以通過立即數尋址的方式實現,也可以通過基址尋址的方式實現。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章