C ++中的常量标识符处理方式不同吗?

时间:2013-12-21 09:21:51

标签: c++ const compiler-optimization variable-names

我们知道常量变量的值是不可变的。但是我们可以使用常量变量的指针来修改它。

#include <iostream>

int main()
{
    const int integer = 2;
    void* tmp = (void*)&integer;
    int* pointer = (int*)tmp;

    (*pointer)++;

    std::cout << *pointer << std::endl;
    std::cout << integer << std::endl;

    return 0;
}

该代码的输出是:

3
2

所以,我混淆了我在地球上修改过的东西? integer代表什么?

5 个答案:

答案 0 :(得分:4)

修改const未定义。编译器可以自由地将const值存储在内存的只读部分中,并在您尝试更改它们时抛出错误(免费,无需)。 未定义的行为很差,不合需要并且要避免。总之,不要这样做。

PS integerpointer是代码中的变量名称,不是特别好的名字。

答案 1 :(得分:3)

你使用了不安全的C风格的强制转换来抛弃常量。 C ++本身并不是一种安全的语言,所以你可以做那样疯狂的事情。这并不意味着你应该。实际上,你根本不应该在C ++中使用C风格的强制转换 - 而是使用reinterpret_cast,const_cast,static_cast和dynamic_cast。如果你这样做,你会发现修改const值的方法是使用const_cast,这正是语言的设计方式。

答案 2 :(得分:0)

这是一种未定义的行为。您获得的输出取决于编译器。 对此行为的一种可能解释如下。

当您将integer声明为常量,并在表达式中使用它时,编译器优化并将其替换为您已分配给它的常量文字。 但是,&integer指向的内存位置的实际内容已更改。编译器只是忽略了这个事实,因为你已经将它定义为常量。

Const Correctness in C++。请注意本页“The Const_cast Operator”部分上方的汇编器输出。

答案 3 :(得分:0)

您正在涉足未定义的行为领域。

如果你写

void* tmp = &integer;

编译器会给你一个错误。如果你写了好的C ++代码并写了

void* tmp = static_cast<void*>(&integer);

编译器仍然会给你一个错误。但是你继续使用C风格的不受保护的演员阵容,这使得编译器没有选择,只能做你告诉它的事情。

编译器有几种方法可以解决这个问题,其中最重要的是:

  1. 可能需要代码段中某个位置的地址,例如,该值被加载到寄存器中。
  2. 可能需要类似值的位置地址。
  3. 它可能会通过将值推入堆栈,获取位置的地址,然后弹出堆栈来创建临时值。
  4. 您必须查看生成的程序集,以查看编译器喜欢哪种变体,但在一天结束时:不执行它是未定义这意味着下次升级编译器或在不同系统上构建或更改优化器设置时,行为可能会发生变化。

    考虑

        const char h = 'h';
        const char* hello = "hello";
        const unsigned char num = 2 * 50 + 2 * 2; // 104 == 'h'
        arg -= num; // sub 104, eax
    
        char* ptr = (char*)(&h);
    

    编译器可以选择专门为'ptr'存储'h',或者它可以选择让'ptr'指向hello中的'h'。或者它可以选择在指令'sub 104,eax'中取值104的位置。

答案 4 :(得分:-1)

const关键字只是编译器的提示。编译器检查变量是否为const,如果直接修改const变量,编译器会产生错误。但是没有用于保护const变量的变量存储机制。因此操作系统无法知道哪个变量是const。