为什么编译器允许你在这里“写”一个const变量?

时间:2022-07-21 01:44:42

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;

7 个解决方案

#1


7  

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. Only const_cast<> allows you to do that.

c型类型的强制转换允许您像您的示例中那样抛弃一致性。在c++中,您通常会使用新的样式强制类型转换,比如static_cast<>,它不允许您放弃对持久性的依赖。只有const_cast<>允许您这样做。

#2


9  

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.

强制转换是你告诉编译器“我知道我在做什么”的一种方式,所以它不会抱怨。不幸的是,在此实例中,您将调用未定义的行为。

#3


4  

To be equivalent, the 2nd line of the 2nd snippet

为了等价,第2段的第2行

int *ptr = ptr2const;      // as expected error is raised here

should be written as

应该写成

int *ptr = (int *)ptr2const;

#4


2  

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.

因为C为了获得更快的速度而放弃了很多类型安全。它不能阻止你做不正确的事情。它可能试图警告您正在做不正确的事情,但是如果这是您的目标,您可以始终围绕编译器工作。

#5


2  

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.

将常量转换为字符串,您可能会发现,虽然编译器会让您丢弃const(尽管可能是不可取的),但是链接器可能会将常量字符串放在只读内存中,导致运行时崩溃。

#6


1  

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).

C风格的类型强制转换(如(int*)在消除一致性方面与c++ const_cast等价,因此您可以通过使用它们来避免一致性,尽管不建议使用它们(可能导致未定义的行为)。

int main()
{
    const int x = 1;
    (int&)x = 2;
    std::cout << x << std::endl;
}

On my system, the above writes 1 to stdout. You might experience different behaviour.

在我的系统上,上面写1到stdout。你可能会经历不同的行为。

On the other hand...

另一方面……

void foo(const int& x)
{
    (int&)x = 2;
}

int main()
{
    int x = 1;
    foo(x);
    std::cout << x << std::endl;
}

This writes 2 for me. The difference is that the const used in foo is const as a type qualifier, while in the main 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 a const_cast or C-style cast to cast away const.

这是2。不同的是,foo中使用的const是const作为类型限定符,而在第一个示例的main中,它被用作存储类。查看变量是否由const声明为存储类并不总是很容易,所以最好不要依赖const_cast或c风格的cast来丢弃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.

最好在大多数情况下使用static_cast,因为这会在编译时以编译错误的形式警告您任何可疑行为。

#7


0  

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.

如果您在全局/静态变量上尝试此操作,您将很快发现,大多数实现都可以并确实执行const,方法是将变量放在只读内存中,该内存可以在程序的多个实例之间共享。

#1


7  

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. Only const_cast<> allows you to do that.

c型类型的强制转换允许您像您的示例中那样抛弃一致性。在c++中,您通常会使用新的样式强制类型转换,比如static_cast<>,它不允许您放弃对持久性的依赖。只有const_cast<>允许您这样做。

#2


9  

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.

强制转换是你告诉编译器“我知道我在做什么”的一种方式,所以它不会抱怨。不幸的是,在此实例中,您将调用未定义的行为。

#3


4  

To be equivalent, the 2nd line of the 2nd snippet

为了等价,第2段的第2行

int *ptr = ptr2const;      // as expected error is raised here

should be written as

应该写成

int *ptr = (int *)ptr2const;

#4


2  

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.

因为C为了获得更快的速度而放弃了很多类型安全。它不能阻止你做不正确的事情。它可能试图警告您正在做不正确的事情,但是如果这是您的目标,您可以始终围绕编译器工作。

#5


2  

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.

将常量转换为字符串,您可能会发现,虽然编译器会让您丢弃const(尽管可能是不可取的),但是链接器可能会将常量字符串放在只读内存中,导致运行时崩溃。

#6


1  

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).

C风格的类型强制转换(如(int*)在消除一致性方面与c++ const_cast等价,因此您可以通过使用它们来避免一致性,尽管不建议使用它们(可能导致未定义的行为)。

int main()
{
    const int x = 1;
    (int&)x = 2;
    std::cout << x << std::endl;
}

On my system, the above writes 1 to stdout. You might experience different behaviour.

在我的系统上,上面写1到stdout。你可能会经历不同的行为。

On the other hand...

另一方面……

void foo(const int& x)
{
    (int&)x = 2;
}

int main()
{
    int x = 1;
    foo(x);
    std::cout << x << std::endl;
}

This writes 2 for me. The difference is that the const used in foo is const as a type qualifier, while in the main 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 a const_cast or C-style cast to cast away const.

这是2。不同的是,foo中使用的const是const作为类型限定符,而在第一个示例的main中,它被用作存储类。查看变量是否由const声明为存储类并不总是很容易,所以最好不要依赖const_cast或c风格的cast来丢弃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.

最好在大多数情况下使用static_cast,因为这会在编译时以编译错误的形式警告您任何可疑行为。

#7


0  

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.

如果您在全局/静态变量上尝试此操作,您将很快发现,大多数实现都可以并确实执行const,方法是将变量放在只读内存中,该内存可以在程序的多个实例之间共享。