-2

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

#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

4

5 回答 5

4

修改consts 是未定义的。编译器可以自由地将const值存储在内存的只读部分中,并在您尝试更改它们时抛出错误(自由,没有义务)。未定义的行为是不良的、不可取的并且应该避免。总而言之,不要那样做。

PSintegerpointer是代码中的变量名,不是特别好的名称。

于 2013-12-21T09:31:28.873 回答
3

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

于 2013-12-21T09:24:30.577 回答
0

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

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

请参阅C++ 中的常量正确性。请注意本页“Const_cast Operator”部分上方的汇编器输出。

于 2013-12-21T10:15:25.603 回答
0

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

如果你写

void* tmp = &integer;

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

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

编译器仍然会给你一个错误。但是您继续使用了 C 风格的无保护强制转换,这使编译器别无选择,只能按照您的指示去做。

编译器有几种方法可以处理这个问题,尤其是:

  1. 它可能采用代码段中某个位置的地址,例如,该值被加载到寄存器中。
  2. 它可能采用具有相似值的位置的地址。
  3. 它可能会通过将值压入堆栈,获取该位置的地址,然后弹出堆栈来创建一个临时值。

您必须查看生成的程序集以查看您的编译器更喜欢哪个变体,但归根结底:不要这样做它是未定义的,这意味着下次您升级编译器或在不同的系统上构建或更改优化器设置,行为可能会改变。

考虑

    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 的位置。

于 2013-12-21T10:34:36.837 回答
-1

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

于 2013-12-21T09:36:10.747 回答