我想知道是否可以通过指针隐式更改常量变量的值.我想出的例子如下:

#include <stdio.h>

int main(void) {

  const int const_num = 10;
  printf("const_num value: %d, const_num address: %p\n", const_num, &const_num);

  void* ptr = (void*)&const_num;
  printf("ptr value: %p, ptr reference value %d\n", ptr, *(int*)ptr);

  *(int*)ptr = 20;
  printf("ptr value: %p, ptr reference value %d\n", ptr, *(int*)ptr);
  printf("const_num value: %d, const_num address: %p\n", const_num, &const_num);

  return 0;
}

答案是,无论您 Select 哪种方式,都不能更改常量变量的值.但令我头疼的是输出的行为.前一个程序的输出如下所示:

const_num value: 10, const_num address: 0x16af26db8
ptr value: 0x16af26db8, ptr reference value 10
ptr value: 0x16af26db8, ptr reference value 20
const_num value: 10, const_num address: 0x16af26db8

因此,尽管const_num保持其初始值,但指针引用的相同内存地址(0x16af26db8)中的对象已从10转换为20.对此有没有可行的解释,或者它被认为是undefined种行为?

推荐答案

我想知道是否可以通过指针隐式更改常量变量的值.

C标准并不禁止你try ,你可能会成功,也可能不会成功.

当程序试图修改定义为const的对象时,该行为不是由C标准定义的,因为C 2018 6.7.3 7规定:

如果试图通过使用具有非常量限定类型的左值来修改使用常量限定类型定义的对象,则行为为Unfined…

这并不意味着你不能try .对于静态对象(任何在函数外声明的对象或使用static声明的对象),try 很可能会因内存访问冲突而失败,因为现代通用多用户系统通常将静态const对象放在内存中标记为只读.

使用堆栈上定义的对象(自动存储持续时间),系统无法将内存标记为只读,因为堆栈既用于const个对象,也用于非const个对象.即使为const个对象创建了单独的堆栈,也不能将其标记为程序只读,因为每次进入函数时,程序都必须初始化自动的const个对象.因此,每次输入包含const个对象的函数时,程序都必须将const堆栈标记为可写,对其上的对象进行初始化,将const堆栈标记为只读,然后继续执行函数.这将为该计划增加相当大的管理费用.

因此,内存中通常会自动存储const个对象,您可以对其进行修改.然而,如果您修改了一个const对象的内存,这并不意味着您的程序将表现为该对象已被修改!这是因为编译器优化了程序,并不总是从内存中获取对象的值.

对于使用const定义的对象,编译器知道只有在该对象未修改的情况下才定义程序行为.它知道允许它的行为就像对象从未被修改过一样.因此,当您的程序执行printf("const_num value: %d, const_num address: %p\n", const_num, &const_num);时,编译器不必生成从内存加载const_num的代码.相反,有效地发生的是编译器可以推理"我不需要从内存加载const_num,因为我知道它被初始化为10,并且我被允许假定它没有改变.所以我可以用10作为printf的自变量."

因此,编译器生成将10传递到printf的代码,而不从内存中加载值const_num.

C++相关问答推荐

我可以动态分配具有空类型函数的矩阵吗?

如何将FileFilter添加到FileDialog GTK 4

如何创建由符号组成的垂直结果图形?

从组播组地址了解收到的数据包长度

GLIBC:如何告诉可执行文件链接到特定版本的GLIBC

加密解密工作正常,但返回错误0x80090005

在循环中复制与删除相同条件代码的性能

Flose()在Docker容器中抛出段错误

处理来自浏览器的HTTP请求

无法识别C编程语言的语法,如书中所示

为什么二进制文件的大小不会随着静态数据的大小而增加?

在文件描述符上设置FD_CLOEXEC与将其传递给POSIX_SPOWN_FILE_ACTIONS_ADCLOSE有区别吗?

为什么我在我的代码中得到错误和退出代码-1073741819(0xC0000005),但如果我添加了一个不相关的打印语句,它仍然有效?

为什么GCC不能在 struct 初始值设定项中以sizeof作为条件的三进制中处理复合文字的编译时求值?

C: NULL>;NULL总是false?

x86-64平台上的int_fast8_t大小与int_fast16_t大小

指向返回 struct 成员的指针,安全吗?

在C中定义函数指针?

c中数组上显示的随机元素

K&R 练习 1-24