指向静态字符的 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。它是一种检测堆栈集中攻击的内存保护机制。