C语言字符数组的初始化研究

来源:互联网 发布:手机淘宝怎样赚淘金币 编辑:程序博客网 时间:2024/04/30 02:55

有一天一个朋友问了我一个很有意思的问题。他问我如果用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.typemain, @functionmain:.LFB2:pushq%rbp.LCFI0:movq%rsp, %rbp.LCFI1:movl%edi, -20(%rbp)movq%rsi, -32(%rbp)movq.LC0(%rip), %raxmovq%rax, -16(%rbp)movl.LC0+8(%rip), %eaxmovl%eax, -8(%rbp)movb$97, -15(%rbp)movl$0, %eaxleaveret.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.globlmain.typemain, @functionmain:.LFB0:.cfi_startprocpushq%rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq%rsp, %rbp.cfi_def_cfa_register 6movl%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, %eaxpopq%rbp.cfi_def_cfa 7, 8ret.cfi_endproc.LFE0:.sizemain, .-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字符串18190431766C6C6568lleh18700780636F77206Fow o6581362646C72dlr从上面两个列子可以看出采用什么方式初始化字符串是根据编译器的不同而不同的,可以通过立即数寻址的方式实现,也可以通过基址寻址的方式实现。




原创粉丝点击