以下是两种具有相同输出的代码片段。
char *p = "abc";
::printf("%s",p);
和
::printf("%s","abc");
“abc”字符串存储在内存中的位置有什么不同吗?
我曾经听说在第二个代码中,“abc”字符串由编译器放在只读内存中(.text部分?)
如何判断代码中的这种差异?
非常感谢。
我目前的理解是:
当我们写:
char *p="abc"
虽然这似乎只是 声明性声明 ,但实际上编译器会生成许多 命令性说明 为了它。这些指令将在包含方法的堆栈框架内分配适当的空间,它可以是这样的:
subl %esp, $4
然后将“abc”字符串的地址移动到该分配的空间,它可能是这样的:
movl $abc_string_address, -4(%ebp)
“abc”字符串存储在可执行文件映像中。但是在内存中它(我的意思是字符串)将被加载完全取决于编译器/链接器的实现,如果它被加载到进程的地址空间的只读部分(即存储器页面的保护位标记为只读,然后p是只读指针,如果它被加载到r / w部分,则p是可写的。
如果我错了,请纠正我。现在我正在查看gcc生成的汇编代码,以确认我的理解。我很快就会再次更新这个帖子。
答案 0 :(得分:3)
存储字符串文字的位置没有区别。唯一的区别是前者还在堆栈上为变量分配空间来存储指针。
答案 1 :(得分:3)
“abc”字符串存储在内存中的位置有什么不同吗?
不,两者都是如此。字符串文字存储在只读段中。但是,如果将变量声明为char [],它将被复制到堆栈中,即不是只读的。
答案 2 :(得分:1)
除了第一个在堆栈上分配的char指针之外没有区别。
它们都使用字符串文字,用双引号分隔。
答案 3 :(得分:1)
是的,它不会存储在不同的位置,它们都是编译时知道的变量,因此编译器会生成汇编代码,而“abc”字符串将在数据段上,即初始化数据。 .bss部分用于单位化数据。
尝试使用gcc和-s选项进行编译。它将生成一个.s
文件,它是汇编代码。 “abc”变量将位于.rodata段下,与NASM程序集的.data相同。
如果你不想做这项工作,这是汇编代码:
这是char * c =“abc”; printf(“%s \ n”,c); 注意这个文件的代码行多于另一个,因为这段代码分配了一个指针变量,并打印了这个变量,另一个解决方案不使用变量,它只是引用一个静态的内存地址。
.file "test.c"
.section .rodata
.LC0:
.string "abc"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl $.LC0, 28(%esp)
movl 28(%esp), %eax
movl %eax, (%esp)
call puts
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
这适用于printf(“abc \ n”);
.file "test2.c"
.section .rodata
.LC0:
.string "abc"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
movl $.LC0, (%esp)
call puts
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
要编辑:
我认为任何编译器都不会将p
放在只读内存上,因为你在代码中声明它是一个变量,它不是编译器生成的隐藏/保护变量,它是一个变量你可以随时使用。
如果执行char* p = "abc";
,编译器会将指针的大小分配给堆栈,并且在后面的指令中,它将插入“abc”字符串的内存地址(现在将其放入只读)寄存器,如果编译器需要注册,则将其值保存到堆栈中。
如果执行printf("abc");
,则不会对变量进行分配,因为编译器在编译时知道字符串的值,所以它只是在那里插入一个数字(相对于可执行文件的开头)并且它可以读取内存的那部分内容。
在此选项中,您可以编译它,生成.exe,然后使用HEX编辑器,并搜索“abc”字符串,并将其更改为“cba”或其他任何内容(可能它将是第一行或其中一行)最后一个),如果编译器像这样生成一个简单的.exe,这很可能。