【问题标题】:Why does a constant variable value change when it is declared locally? [duplicate]为什么常量变量值在本地声明时会发生变化? [复制]
【发布时间】:2015-08-26 11:29:36
【问题描述】:

场景 1:当 const 变量在 main() 内声明时,即本地化

#include <stdio.h>
#include <conio.h>

main()
{
    const int a = 45;

    * ((int*)&a)=50;

    printf("%d\n",a);
    getch();

}

输出MVC++:

a=50

场景 2:当 const 变量在 main() 之外声明时,即全局化

#include <stdio.h>
#include <conio.h>
const int a = 45;
main()
{

    * ((int*)&a)=50;

    printf("%d\n",a);
    getch();

}

输出MVC++:

未处理的异常...访问冲突。

我了解为什么在尝试修改全局定义的 const 变量时会出错。但是,为什么当我尝试修改本地定义的 const 变量时没有收到错误消息?

【问题讨论】:

  • 您不会收到错误消息,因为 C 风格的强制转换会默默地抛弃 constness。这只是你永远不应该使用 C 风格转换的原因之一
  • 正如其他人所说,你有未定义的行为,所以两者都很糟糕。也就是说,全局变量倾向于崩溃的原因是操作系统加载程序可以将所有全局常量放入内存并将其标记为只读,因此您会收到一个很好的访问冲突消息。局部变量可能在堆栈上,并且在创建和销毁自动变量时,在 CPU 级别上不断地临时生成堆栈的一部分const 是不切实际的(由于内存页面大小的影响和性能损失) .
  • @Tony D 感谢您提供如此详细的解释。它真的帮助了我。
  • 我投票决定将此问题作为题外话结束,因为今天的“我做了一件明显很糟糕的事情,我希望它得到解释”是“我通过指针更改了 const”。 DownCloseVote....

标签: c constants


【解决方案1】:

试图修改 const 变量的内容是未定义的行为,这意味着它是一个错误,任何事情都可能发生。

因此不能保证第一个案例也不会崩溃。为什么您碰巧侥幸逃脱,可能是因为本地范围内的 const 变量往往在运行时存储在堆栈中。这意味着它恰好是您可以写入的内存区域。但是,当您在文件范围内发布它时,它最终会出现在只读内存段中,从而导致崩溃。

【讨论】:

  • 作为唯一一个真正回答问题的人做得很好,实际上解释了为什么结果不同,即使任何一个结果都是有效的。
  • @hvd 但是,应该注意的是,检查未定义行为的结果为何以某种方式结束,通常是毫无意义的做法。最好反过来研究因果关系:访问冲突的原因可能是什么?
  • @Lundin 我想我知道先生,但我不喜欢实时这样做,因为最近的答案大部分时间与 OP 正在进行的后续编辑相冲突。所以,我留下了笔记。希望我能理解。
  • 感谢这么快的回复,我的疑问现在解决了
  • 本地范围的 const 是否总是驻留在堆栈上?因为我通常在函数中定义 const 数组表
【解决方案2】:

您的代码生成undefined behaviour。 如果您尝试修改任何const 变量通过 非const 限定类型变量(例如:通过cast 去掉const-ness),它是UB。

引用C11 标准,第 §6.7.3 章,(类型限定符

如果尝试通过使用来修改使用 const 限定类型定义的对象 具有非 const 限定类型的左值,行为未定义。 [...]

FWIW,这不依赖于在全局范围或局部范围内定义的变量,在这两种情况下它都是 UB。

正如Mr. Lundin 在他的answer 中很好地描述的那样,对于这种 情况,它可能会发生,就像局部范围const 变量在堆栈中占据了它的位置,因此变得可修改,不知何故.因此,您没有看到访问冲突错误 (crash) 。但是,请记住,标准无法保证接近

【讨论】:

    【解决方案3】:

    修改const 对象是未定义的行为

    N3337 [dcl.type.cv]/4: 除了可以修改声明为mutable 的任何类成员外,任何在const 对象的生命周期内修改其生命周期的尝试都会导致未定义的行为。

    两者的行为以及您能想象的任何其他事情都是有效的。

    【讨论】:

      【解决方案4】:

      一旦您有一个声明为const 的变量,您就不应使用指向该位置的指针来更改存储的值。这会调用未定义的行为。

      const 变量的存储位置完全取决于系统,它们大多存储在只读位置,因此尝试写入它会导致访问冲突

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-03-25
        • 1970-01-01
        • 2011-07-06
        • 2015-11-30
        • 1970-01-01
        • 2017-02-06
        • 2016-12-28
        • 1970-01-01
        相关资源
        最近更新 更多