为什么编译器允许你“写”这里有一个常量变量吗?
为什么你可以这样欺骗编译器:
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;
Why can you kind of cheat compiler this way:
const int a = 5;
*((int*)&a)=5; // VC/armcc does not complain
when above is "abridged" equivalent of this:
const int *ptr2const = &a;
int *ptr = ptr2const; // as expected error is raised here
*ptr = 5;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
强制转换是告诉编译器“我知道我在做什么”的方式,所以它不会抱怨。不幸的是,在这种情况下,您将调用未定义的行为。
Casting is your way of telling the compiler "I know what I'm doing", so it doesn't complain. Unfortunately, in this instance, you will invoke undefined behaviour.
C 风格的强制转换允许您像示例中那样放弃常量。在 C++ 中,您通常会使用新的样式强制转换,例如
static_cast<>
,它不允许您放弃常量。只有const_cast<>
允许您执行此操作。C-style casts allow you to cast away constness like in your example. In C++, you would normally use the new style casts such as
static_cast<>
, which don't allow you to cast away constness. Onlyconst_cast<>
allows you to do that.为了等效,第二个片段的第二行
应写为
To be equivalent, the 2nd line of the 2nd snippet
should be written as
因为 C 抛弃了很多类型安全,以获得更快的速度。它不能阻止你做不正确的事情。它可能会尝试警告您正在做不正确的事情,但如果这是您的目标,您总是可以绕过编译器。
Because C throws away a lot of type safety in order to gain a lot of speed instead. It cannot prevent you from doing incorrect things. It may try to warn you that you are doing incorrect things, but you can always work around the compiler if that is your goal.
将常量转换为字符串,您可能会发现,虽然编译器会让您放弃
const
(尽管这可能是不可取的),但链接器可能会将常量字符串放入在只读内存中导致运行时崩溃。Convert your constant to a string and you may find that while the compiler will let you cast away the
const
(inadvisable though it may be), the linker may put the constant string in read-only memory leading to a runtime crash.C 风格的强制转换,例如
(int*)
等价于 C++const_cast
,它们能够抛弃常量性,因此您可以通过使用它们来回避常量正确性,尽管不推荐这种使用(可能导致未定义的行为)。在我的系统上,上面的代码将
1
写入标准输出。您可能会遇到不同的行为。另一方面......
这为我写了
2
。不同之处在于,foo
中使用的const
是 const 作为类型限定符,而在第一个示例的main
中,它被用作类型限定符。存储类。查看变量是否使用 const 声明为存储类并不总是那么容易,因此最好不要依赖const_cast
或 C 风格强制转换来放弃 const。在大多数情况下最好只使用
static_cast
,因为这会在编译时以编译错误的形式警告您任何可疑行为。C-style casts, such as
(int*)
are equivalent to C++const_cast
in their ability to cast away constness, so you can side-step const-correctness by using them, although such use is unrecommended (can lead to undefined behaviour).On my system, the above writes
1
to stdout. You might experience different behaviour.On the other hand...
This writes
2
for me. The difference is that theconst
used infoo
is const as a type qualifier, while in themain
in the first example it was used as a storage class. It's not always easy to see whether a variable was declared with const as a storage class, so it's best not to rely on aconst_cast
or C-style cast to cast away const.It's best just to use
static_cast
in most situations as this will warn you at compile time of any suspect behaviour in the form of a compile error.这只“有效”,因为变量是本地变量,并且实现通常无法在本地(自动)变量上强制执行常量性(至少在获取变量地址的情况下不会)。但就语言规范而言,这属于未定义行为的领域。
如果您在全局/静态变量上尝试此操作,您很快就会发现大多数实现可以并且确实通过将变量放入来强制
const
只读内存,可以在程序的多个实例之间共享。This only "works" because the variable is local, and implementations have no way to enforce const-ness on a local (automatic) variable in general (at least not if the address of the variable is ever taken). But as far as the language specification is concerned, this is in the realm of undefined behavior.
If you try this on a global/static variable, you'll quickly find that most implementations can and do enforce
const
by putting the variable in read-only memory which can be shared between multiple instances of your program.