为什么你可以这样欺骗编译器:
const int a = 5;
*((int*)&a)=5; // VC/armcc does not complain
当上述内容被“删节”时相当于:
const int *ptr2const = &a;
int *ptr = ptr2const; // as expected error is raised here
*ptr = 5;
答案 0 :(得分:9)
Casting是告诉编译器“我知道我在做什么”的方式,所以它不会抱怨。不幸的是,在这种情况下,您将调用未定义的行为。
答案 1 :(得分:7)
C风格的强制转换允许你像你的例子一样抛弃常量。在C ++中,您通常会使用新的样式转换,例如static_cast<>
,它们不允许您丢弃constness。只有const_cast<>
允许您这样做。
答案 2 :(得分:4)
相当于第二个片段的第二行
int *ptr = ptr2const; // as expected error is raised here
应该写成
int *ptr = (int *)ptr2const;
答案 3 :(得分:2)
因为C为了获得很大的速度而抛弃了很多类型的安全性。它不能阻止你做错误的事情。它可能会试图警告您,您正在做错误的事情,但如果这是您的目标,您可以始终解决编译器问题。
答案 4 :(得分:2)
将你的常量转换为字符串你可能会发现虽然编译器会让你抛弃const
(尽管它可能是不可取的),但链接器可能会放置常量字符串在只读内存中导致运行时崩溃。
答案 5 :(得分:1)
C样式的强制类型转换(例如(int*)
)在抛弃const的能力上等同于C ++ const_cast
,所以你可以通过使用它们来支持const-correctness,尽管这种用法是未经推荐的(可能导致未定义的行为)。
int main()
{
const int x = 1;
(int&)x = 2;
std::cout << x << std::endl;
}
在我的系统上,上面将1
写入stdout。您可能会遇到不同的行为。
另一方面......
void foo(const int& x)
{
(int&)x = 2;
}
int main()
{
int x = 1;
foo(x);
std::cout << x << std::endl;
}
这为我写2
。不同之处在于const
中使用的foo
是const作为类型限定符,而在第一个示例中的main
中它被用作存储类。使用const作为存储类声明变量是否并不总是很容易,因此最好不要依赖const_cast
或C样式转换来抛弃const。
最好只在大多数情况下使用static_cast
,因为这会在编译时以编译错误的形式警告您任何可疑行为。
答案 6 :(得分:0)
这只是“有效”,因为变量是本地的,并且实现无法在一般的本地(自动)变量上强制执行常量(至少在变量的地址不被采用时)。但就语言规范而言,这是未定义行为的范畴。
如果你在全局/静态变量上尝试这个,你会很快发现大多数实现可以和执行强制执行const
只读存储器,可以在程序的多个实例之间共享。