如何将两个数据保存在 C 的同一内存位置?

How is it possible to save two data in the same memory location on C?

我正在学习 C 语言,特别是指针,我有这个小问题。

如何将两个数据保存在 C 的同一个内存位置?看我的代码:

#include <stdio.h>

int main()
{
    const int y = 2;
    int *const ptr_y = &y;

    *ptr_y = 4;
    
    //Values
    printf("%d\n", y);
    printf("%d\n\n", *ptr_y);

    //Memory locations
    printf("%p\n", &y);
    printf("%p\n", ptr_y);

    return (0);
}

输出:

2
4

0x7ffeeb501788
0x7ffeeb501788

我期望的输出:

4 
4 

0x7ffeeb501788 
0x7ffeeb501788 

我想知道这段代码在内部是如何工作的。

重要提示:我知道常量指针未正确声明 (const int *ptr_y)。

代码调用 undefined behavior 因为您不能更改 const 变量的内容,因此输出没有意义,根据上面链接的未定义行为的定义,它可以是任何东西.

您没有将数据保存在两个不同的位置,它是同一个位置。

y 存储在某个(内存)位置,该位置有一个地址,ptr_y 是一个指针,它包含相同的内存地址,因为您使用 address-of 分配了它运算符 &:

int *const ptr_y = &y;

上面的赋值丢弃了 const 限定符,因此,编译器允许您尝试将 y 的值更改为 *ptr_y = 4,这仍然无效但由于错误的分配,它成为可能。如果您使用:

,您应该始终尊重指针中的 const 限定符
const int y = 2;
const int* ptr_y = &y;

编译器不会让你这样做的:

*ptr_y = 4;

error: assignment of read-only location '*ptr_y'

使用正确的代码,通过使用 * 运算符取消对 ptr_y 的引用,您将访问存储在 ptr_y 中的地址,顺便说一下,它是 y 的地址,所以它是相同的内存地址,您只是以两种不同的方式访问它:

int y = 2; // non const

int *const ptr_y = &y; // constant pointer is allowed

*ptr_y = 4;

//Values
printf("%d\n", y);
printf("%d\n\n", *ptr_y);

//Memory locations
printf("%p\n", (void*)&y); // %p specifier expects void*
printf("%p\n", (void*)ptr_y); 
4
4

0x7ffd0f9aee34
0x7ffd0f9aee34

首先,int *const ptr_y = &y; 不是有效的 C,所以如果你的编译器生成了一个可执行文件,尽管有这段代码,它的所有行为都是无效的。如果您没有收到来自编译器的消息,则意味着您的编译器配置为 non-standard。参见 What compiler options are recommended for beginners learning C?

严格来说printf("%p\n", &y);也应该转换为(const void*)&y


C 标准未指定 const int y = 2; 存储值 2 的位置。它可以在寄存器中,在堆栈上,在标记为“只读”(.rodata 或类似)的 read/write 内存中,或者它可以存储在真正的 read-only 内存中,例如闪存,以防万一嵌入式系统。

如果您对该内存位置进行写访问,则该行为未由 C 标准定义。 Undefined behavior = 任何事情都可能发生,包括:

  • 它可以更新内存,下次你读回 4
  • 它可以更新内存,但编译器优化器不会生成代码来读回它,所以你仍然得到 2
  • 编译器可以忽略生成写入尝试的代码。
  • 它可能是真实的 read-only 内存,所以当您尝试写入它时,没有任何反应。
  • 它可能是 read-only 内存并受到保护,因此写入尝试会导致硬件异常或类似情况。

总的来说,分析调用未定义行为时到底发生了什么(症状)并没有太大意义。重要的是理解为什么代码包含未定义的行为(根本原因)。