考虑以下代码:
#include <stdio.h>
#define main_arg int argc, char *argv[]
int main(main_arg)
{
static char chr = '5' - '0'; // Dec 5
int *p = &chr; // 4 bytes pointer
printf("Result: %i", *p);
return(0);
}
Result: 5
为什么我必须将chr
声明为静态以获得适当的值?
如果我不使用静态,p
将读取4个字节的总数,其中3个将是&#34;随机&#34;。但如果一个字节chr
表示位于静态存储器中,那不会发生吗?
这是未定义的行为,结果是不确定的,它只是这样,意外地(我一直在尝试)?
答案 0 :(得分:3)
当你声明一个变量static时,它被分配在.BSS或.data中,并且该区域全部归零,所以即使你已经将chr初始化为5,巧合的是chr地址之前和之前的所有字节都是零
这是一种验证方法。 (可能在您的系统上有所不同)
(gdb) x/16w &chr - 16
0x601030: 0 0 0 0
0x601040 <chr.2180>: 5 0 0 0
0x601050: 0 0 0 0
0x601060
以下是各节。
06:43:46~ $ readelf -s a.out
53: 0000000000601030 0 NOTYPE WEAK DEFAULT 24 data_start
54: 0000000000601041 0 NOTYPE GLOBAL DEFAULT 24 _edata
55: 00000000004005e4 0 FUNC GLOBAL DEFAULT 14 _fini
56: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@@GLIBC_2.2.5
57: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_
58: 0000000000601030 0 NOTYPE GLOBAL DEFAULT 24 __data_start
59: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
60: 0000000000601038 0 OBJECT GLOBAL HIDDEN 24 __dso_handle
61: 00000000004005f0 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used
62: 0000000000400570 101 FUNC GLOBAL DEFAULT 13 __libc_csu_init
63: 0000000000601048 0 NOTYPE GLOBAL DEFAULT 25 _end
64: 0000000000400440 0 FUNC GLOBAL DEFAULT 13 _start
65: 0000000000601041 0 NOTYPE GLOBAL DEFAULT 25 __bss_start
66: 000000000040052d 53 FUNC GLOBAL DEFAULT 13 main
67: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
答案 1 :(得分:3)
char数据类型是一个字节。您使用整数点“int * P”指向chr的单字节内存位置,但C将此视为四字节位置,因为它认为它是指向int的指针,其长度为四个字节。基于你的5的结果,显然当你将它声明为静态时,chr的位置恰好跟随零,因此结果只是5.当它没有被声明为静态时,它就在堆栈上并且只是选择在chr的位置之后的内存中的不同值。无论如何,使用* P引用它不应该存储的内存并且将产生不可预测的结果。
顺便说一下,你的样本将int *声明为“* P”(大写字母P)并稍后将其引用为“* p”(小写p),因此该代码不会按原样运行。
答案 2 :(得分:3)
在某些系统中,您的代码可能无法运行,主要是因为对齐。在某些RISC系统中,char
可以与任何对齐,但是int
必须与4个字节对齐,例如。在这种情况下,如果您尝试取消引用这样的指针,某些内存访问保护机制可能会发出中断,整个程序将立即失败。
在你的情况下,假设你在Linux中运行,使用intel cpu,使用gcc编译,chr
将驻留在.data
段中,并且它的所有不相关部分将最有可能设置为0。
但同样,你以错误的方式访问内存,一切都应该发生,因为它是一个未定义的行为。
提供更多信息,如果你删除static
,并在上述环境中运行该程序,你读取的额外值不是&#34; random&#34;,但它是随机的,字面意思。这称为canary
。它是一种用于检测堆栈聚焦攻击的内存保护机制。