假设我有简单的C程序,我用gcc -o hello hello.c
编译它:
#include<stdio.h>
main()
{
printf("hello");
}
现在我要显示&#34;字符串&#34;使用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$"
并且,正如预期的那样,我可以看到字符串&#34; hello&#34;在二进制文件中。
但是,当我修改我的C
程序并将&#34; hello&#34;作为常数:
#include<stdio.h>
char s[6] = {'h','e','l','l','o','\0' } ;
main()
{
printf("%s\n", s);
}
我没有看到字符串&#34;你好&#34;在二进制文件中。
有人可以解释一下原因吗?
答案 0 :(得分:5)
来自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),唯一的区别是,对字符串文字进行调整会调用 undefined behaviur ,因此编译器可能会选择将它们放入单独的(例如只读)内存位置。
数组类型描述了连续分配的非空集 具有特定成员对象类型的对象,称为元素类型。
静态存储时间的所有对象都应初始化(设置为 程序启动前的初始值。
从更实际的角度来看,除了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
命令的结果,看看它们之间是否存在差异。
答案 1 :(得分:2)
我没有看到字符串&#34;你好&#34;在二进制文件中。
我认为此预期有效行为,因为您不再提供文字"hello"
,而是提供6个单独的char
文字。< / p>