指向静态字符的 int 指针
int pointer that points to a static char
考虑这段代码:
#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 个字节将是 "random"。但是如果 chr
表示的那个字节位于静态内存中,那不会发生吗?
这是未定义的行为吗?结果是不确定的,它只是偶然发生的(我一直在尝试)?
当你声明一个静态变量时,它被分配在.BSS或.data中并且该区域被全部清零,所以即使你将chr初始化为5,巧合的是地址前后的所有字节字符为零
这里有一个验证方法。 (您的系统可能有所不同)
(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
char 数据类型是一个字节。您正在使用整数点 "int *P" 指向 chr 的一个字节内存位置,但 C 会将其视为一个四字节位置,因为它认为它是一个指向长度为四个字节的 int 的指针.根据 5 的结果,显然当您将其声明为静态时,chr 的位置恰好后跟零,因此结果仅为 5。当它未声明为静态时,它位于堆栈中并且只是选择根据 chr 的位置在内存中添加不同的值。无论如何,使用 *P 引用它不应该引用的内存并且会产生不可预知的结果。
顺便说一句,您的示例将 int* 声明为“*P”(大写 P)并稍后将其引用为“*p”(小写 p),因此此代码不会 运行 原样。
在某些系统中,您的代码可能不会 运行,主要是因为对齐。在某些 RISC 系统中,char
可以对齐到任何内容,但是 int
必须对齐到 4 个字节,例如。在这种情况下,如果您尝试像这样取消引用指针,某些内存访问保护机制可能会发出中断,整个程序将立即失败。
在你的情况下,假设你在 Linux 中 运行,使用英特尔 cpu,使用 gcc 编译,chr
将驻留在 .data
段中,并且它的所有不相关部分最有可能设置为 0。
但是,您再次以错误的方式访问内存,一切都应该发生,因为这是未定义的行为。
提供更多信息,如果你在上面的环境中删除static
,而运行那个程序,你读到的额外值不是"random",而是随机的,字面上地。这叫做 canary
。它是一种检测堆栈集中攻击的内存保护机制。
考虑这段代码:
#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 个字节将是 "random"。但是如果 chr
表示的那个字节位于静态内存中,那不会发生吗?
这是未定义的行为吗?结果是不确定的,它只是偶然发生的(我一直在尝试)?
当你声明一个静态变量时,它被分配在.BSS或.data中并且该区域被全部清零,所以即使你将chr初始化为5,巧合的是地址前后的所有字节字符为零
这里有一个验证方法。 (您的系统可能有所不同)
(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
char 数据类型是一个字节。您正在使用整数点 "int *P" 指向 chr 的一个字节内存位置,但 C 会将其视为一个四字节位置,因为它认为它是一个指向长度为四个字节的 int 的指针.根据 5 的结果,显然当您将其声明为静态时,chr 的位置恰好后跟零,因此结果仅为 5。当它未声明为静态时,它位于堆栈中并且只是选择根据 chr 的位置在内存中添加不同的值。无论如何,使用 *P 引用它不应该引用的内存并且会产生不可预知的结果。
顺便说一句,您的示例将 int* 声明为“*P”(大写 P)并稍后将其引用为“*p”(小写 p),因此此代码不会 运行 原样。
在某些系统中,您的代码可能不会 运行,主要是因为对齐。在某些 RISC 系统中,char
可以对齐到任何内容,但是 int
必须对齐到 4 个字节,例如。在这种情况下,如果您尝试像这样取消引用指针,某些内存访问保护机制可能会发出中断,整个程序将立即失败。
在你的情况下,假设你在 Linux 中 运行,使用英特尔 cpu,使用 gcc 编译,chr
将驻留在 .data
段中,并且它的所有不相关部分最有可能设置为 0。
但是,您再次以错误的方式访问内存,一切都应该发生,因为这是未定义的行为。
提供更多信息,如果你在上面的环境中删除static
,而运行那个程序,你读到的额外值不是"random",而是随机的,字面上地。这叫做 canary
。它是一种检测堆栈集中攻击的内存保护机制。