假设我有一个简单的C程序,并使用gcc -o hello hello.c
以下命令进行编译:
#include<stdio.h>
main()
{
printf("hello");
}
现在,我想用该strings
实用程序显示“字符串” :
$ strings hello
/lib64/ld-linux-x86-64.so.2
__gmon_start__
libc.so.6
printf
__libc_start_main
GLIBC_2.2.5
fffff.
l$ L
t$(L
|$0H
hello
;*3$"
和预期的一样,我可以在二进制文件中看到字符串“ hello”。
但是,当我修改C
程序并将“ hello”作为常量时:
#include<stdio.h>
char s[6] = {'h','e','l','l','o','\0' } ;
main()
{
printf("%s\n", s);
}
我不再在二进制文件中看到字符串“ hello”。
有人可以解释为什么吗?
来自man 1 strings
(强调我的):
对于给定的每个文件,GNU字符串将打印至少4个字符长(或下面的选项提供的数字)的可打印字符序列,后跟不可打印字符。默认情况下,它仅打印目标文件的初始化和加载部分中的字符串。对于其他类型的文件,它将打印整个文件中的字符串。
C语言没有将字符串定义为一等公民。它们表示为字符串数组或字符串文字。例如,在这样的基本程序中:
#include <stdio.h>
int main(void)
{
char s[] = "my string";
printf("%s\n", s);
return 0;
}
我们可以合理地说s
数组包含一个字符串。请注意,这是在堆栈上分配的。它具有自动存储期限,与您的问题示例相反,在(和任何)函数s
之外明确定义了存储期限main
。
现在,回到您的问题,两个程序中的两个基础对象都具有相同的特征:
char[6]
和内容相同(C11§6.2.5/ p20),唯一的区别是修改字符串文字会调用未定义的行为,因此编译器可以选择将它们放置在单独的(例如,只读的)内存位置。
数组类型描述具有特定成员对象类型(称为元素类型)的连续分配的非空对象集。
程序启动前,所有具有静态存储持续时间的对象都应初始化(设置为其初始值)。
从更实际的角度来看,除了该strings
命令之外,您还可以使用gdb
调试器(更具体地说是使用x/s
命令)来分析程序。这是基本插图:
$ gcc -g hello.c -o hello
$ gdb -q hello
Reading symbols from /home/grzegorz/hello...done.
(gdb) disas /m main
Dump of assembler code for function main:
6 {
0x00000000004004c4 <+0>: push %rbp
0x00000000004004c5 <+1>: mov %rsp,%rbp
7 printf("%s\n", s);
0x00000000004004c8 <+4>: mov $0x60086c,%edi
0x00000000004004cd <+9>: callq 0x4003b8 <puts@plt>
8 }
0x00000000004004d2 <+14>: leaveq
0x00000000004004d3 <+15>: retq
End of assembler dump.
(gdb) x/s 0x60086c
0x60086c <s>: "hello"
您可能要比较disas
程序的命令结果,看看它们之间是否存在差异。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句