为什么GNU C++编译器允许修改常数? 我通过GDB对C++编写的一个项目进行了研究,发现一个const正在被GNU C++编译器没有警告或错误的修改。

为什么GNU C++编译器允许修改常数? 我通过GDB对C++编写的一个项目进行了研究,发现一个const正在被GNU C++编译器没有警告或错误的修改。,c++,gcc,C++,Gcc,这不是我调试的程序,但这是我亲眼目睹的行为的一个例子: #include <iostream> int main(int argc, char *argv[]) { const int x = 10; int *px = (int *)&x; ++*px; std::cout << "*px: " << *px << "\n"; std::cout << "x: " << x <<

这不是我调试的程序,但这是我亲眼目睹的行为的一个例子:

#include <iostream>

int main(int argc, char *argv[]) {
  const int x = 10;

  int *px = (int *)&x;
  ++*px;

  std::cout << "*px: " << *px << "\n";
  std::cout << "x: " << x << "\n";

  for (int i = 0; i < x; ++i)
    std::cout << i+1 << "\n";

  return 0;
}

就编译器而言,您并不是在修改常量。您正在修改指向非常量int的指针所指向的内容,因为强制转换int*告诉编译器将&x视为

这种所谓的C型铸造是C++提供的最强大的铸件。铸造通常只应在真正必要的范围内进行。在许多情况下,const_cast、static_cast或dynamic_cast就足够了,还有非常强大的reinterpret_cast


C样式转换的行为是应用使编译成功所需的最小功能转换。

就编译器而言,您并不是在修改常量。您正在修改指向非常量int的指针所指向的内容,因为强制转换int*告诉编译器将&x视为

这种所谓的C型铸造是C++提供的最强大的铸件。铸造通常只应在真正必要的范围内进行。在许多情况下,const_cast、static_cast或dynamic_cast就足够了,还有非常强大的reinterpret_cast


C样式转换的行为是应用使编译成功所需的最不强大的转换。

因此结果是不可预测的。编译器不必为未定义的行为生成诊断。。。链接问题很可能是一个复制品,这就是为什么你几乎不应该在C++中使用C风格的转换。更喜欢康斯特演员:为什么投了反对票我不知道这是个糟糕的问题。因此结果是不可预测的。编译器不必为未定义的行为生成诊断。。。链接问题很可能是一个复制品,这就是为什么你几乎不应该在C++中使用C风格的转换。更喜欢康斯特演员:为什么投了反对票我没有意识到这是一个糟糕的问题。好吧,我假设是这样的,但看起来这样的事情至少应该产生一个警告。悄悄地通过编译器是很可怕的。这基本上是C语言的传统,这种类型的转换很常见。事实上,最初,这是唯一可用的转换方法,它允许几乎任何东西。这就是我在回答中提到的引入演员阵容的原因。C样式转换仍然适用于向后兼容性,但不建议使用它。@ffhaddad另一个观点:它通常不会在编译器中静默地运行。通常会出现错误:从“常量int*”到“int*”的转换无效。强制转换告诉编译器闭嘴,我知道我在做什么。@Dabbler:实际上,有人可能会说C风格强制转换是必要的,因为它是唯一允许通过私有继承强制转换的类型。。。这在我的世界里并不常见,但值得一提。在这种情况下,一个康斯特演员不会做同样的事情吗?指责C风格的演员阵容有点误导人。好吧,我假设是这样的,但看起来这样的事情至少应该产生一个警告。悄悄地通过编译器是很可怕的。这基本上是C语言的传统,这种类型的转换很常见。事实上,最初,这是唯一可用的转换方法,它允许几乎任何东西。这就是我在回答中提到的引入演员阵容的原因。C样式转换仍然适用于向后兼容性,但不建议使用它。@ffhaddad另一个观点:它通常不会在编译器中静默地运行。通常会出现错误:从“常量int*”到“int*”的转换无效。强制转换告诉编译器闭嘴,我知道我在做什么。@Dabbler:实际上,有人可能会说C风格强制转换是必要的,因为它是唯一允许通过私有继承强制转换的类型。。。这在我的世界里并不常见,但值得一提。在这种情况下,一个康斯特演员不会做同样的事情吗?指责C风格演员有点误导。
*px: 11
x: 10
1
2
3
4
5
6
7
8
9
10