C/C++ 改变常量的值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/583076/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C/C++ changing the value of a const
提问by fmsf
I had an article, but I lost it. It showed and described a couple of C/C++ tricks that people should be careful. One of them interested me but now that I am trying to replicate it I'm not being able to put it to compile.
我有一篇文章,但我失去了它。它展示并描述了一些人们应该小心的 C/C++ 技巧。其中一个让我感兴趣,但现在我正在尝试复制它,但我无法编译它。
The concept was that it is possible to change by accident the value of a const
in C/C++
这个概念是有可能const
在 C/C++ 中意外改变 a 的值
It was something like this:
它是这样的:
const int a = 3; // I promise I won't change a
const int *ptr_to_a = &a; // I still promise I won't change a
int *ptr;
ptr = ptr_to_a;
(*ptr) = 5; // I'm a liar; a is now 5
I wanted to show this to a friend but now I'm missing a step. Does anyone know what's missing for it to start compiling and working?
我想把这个展示给朋友,但现在我错过了一步。有谁知道它开始编译和工作缺少什么?
ATM I'm getting invalid conversion from 'const int*' to 'int*'but when I read the article I tried and it worked great.
ATM 我收到了从“const int*”到“int*”的无效转换,但是当我阅读这篇文章时,我尝试了,而且效果很好。
回答by sfossen
you need to cast away the constness:
你需要抛弃常量:
linux ~ $ cat constTest.c
#include <stdio.h>
void modA( int *x )
{
*x = 7;
}
int main( void )
{
const int a = 3; // I promisse i won't change a
int *ptr;
ptr = (int*)( &a );
printf( "A=%d\n", a );
*ptr = 5; // I'm a liar, a is now 5
printf( "A=%d\n", a );
*((int*)(&a)) = 6;
printf( "A=%d\n", a );
modA( (int*)( &a ));
printf( "A=%d\n", a );
return 0;
}
linux ~ $ gcc constTest.c -o constTest
linux ~ $ ./constTest
A=3
A=5
A=6
A=7
linux ~ $ g++ constTest.c -o constTest
linux ~ $ ./constTest
A=3
A=3
A=3
A=3
also the common answer doesn't work in g++ 4.1.2
常见的答案也不适用于 g++ 4.1.2
linux ~ $ cat constTest2.cpp
#include <iostream>
using namespace std;
int main( void )
{
const int a = 3; // I promisse i won't change a
int *ptr;
ptr = const_cast<int*>( &a );
cout << "A=" << a << endl;
*ptr = 5; // I'm a liar, a is now 5
cout << "A=" << a << endl;
return 0;
}
linux ~ $ g++ constTest2.cpp -o constTest2
linux ~ $ ./constTest2
A=3
A=3
linux ~ $
btw.. this is never recommended... I found that g++ doesn't allow this to happen.. so that may be the issue you are experiencing.
顺便说一句..这从来没有被推荐过......我发现g++不允许这种情况发生..所以这可能是你遇到的问题。
回答by Adam Rosenfield
Just a guess, but a common question is why one can't convert an int**
to a const int**
, which at first appears to be reasonable (after all, you're just adding a const
, which is normally ok). The reason is that if you could do this, you could accidentally modify a const
object:
只是一个猜测,但一个常见的问题是为什么不能将 an 转换int**
为 a const int**
,这乍一看似乎是合理的(毕竟,您只是添加了 a const
,这通常是可以的)。原因是如果你能这样做,你可能会不小心修改一个const
对象:
const int x = 3;
int *px;
const int **ppx = &px; // ERROR: conversion from 'int**' to 'const int**'
*ppx = &x; // ok, assigning 'const int*' to 'const int*'
*px = 4; // oops, just modified a const object
It's a very non-intuitive result, but the only way to make sure that you can't modify a const
object in this case (note how there are no typecasts) is to make line 3 an error.
这是一个非常不直观的结果,但确保const
在这种情况下不能修改对象的唯一方法(注意没有类型转换)是使第 3 行出错。
You're only allowed to add const
without a cast at the FIRST level of indirection:
您只允许const
在第一级间接添加而不进行强制转换:
int * const *ppx = &px; // this is ok
*ppx = &x; // but now this is an error because *ppx is 'const'
In C++, it is impossible to modify a const
object without using a typecast of some sort. You'll have to use either a C-style cast or a C++-style const_cast
to remove the const
-ness. Any other attempt to do so will result in a compiler error somewhere.
在 C++ 中,const
不使用某种类型转换就不可能修改对象。您必须使用 C 样式转换或 C++ 样式const_cast
来删除const
-ness。任何其他尝试这样做都会在某处导致编译器错误。
回答by Andrew Khosravian
Note any attempt to cast away constness is undefined by the standard. From 7.1.5.1 of the standard:
请注意,标准未定义任何抛弃常量的尝试。从标准的 7.1.5.1 开始:
Except that any class member declared mutable can be modified, any attempt to modify a const object during its lifetime results in undefined behavior.
除了任何声明为 mutable 的类成员都可以修改之外,任何在其生命周期内修改 const 对象的尝试都会导致未定义的行为。
And right after this example is used:
在使用此示例之后:
const int* ciq = new const int (3); // initialized as required
int* iq = const_cast<int*>(ciq); // cast required
*iq = 4; // undefined: modifies a const object
So in short what you want to do isn't possible using standard C++.
简而言之,使用标准 C++ 无法实现您想要做的事情。
Further when the compiler encounters a declaration like
此外,当编译器遇到类似的声明时
const int a = 3; // I promisse i won't change a
it is free to replace any occurance of 'a' with 3 (effectively doing the same thing as #define a 3
)
可以自由地将任何出现的 'a' 替换为 3(实际上与 做同样的事情#define a 3
)
回答by Paul Tomblin
Back in the mists of time, we paleo-programmers used FORTRAN. FORTRAN passed all its parameters by reference, and didn't do any typechecking. This meant it was quite easy to accidentally change the value of even a literal constant. You could pass "3" to a SUBROUTINE, and it would come back changed, and so every time from then on where your code had a "3", it would actually act like a different value. Let me tell you, those were hard bugs to find and fix.
回到时间的迷雾中,我们古程序员使用 FORTRAN。FORTRAN 通过引用传递其所有参数,并且没有进行任何类型检查。这意味着即使是文字常量的值也很容易意外更改。您可以将“3”传递给子程序,它会返回更改,因此从那时起,每次您的代码具有“3”的地方,它实际上都会充当不同的值。让我告诉你,那些是很难找到和修复的错误。
回答by Michael Kristofik
Did you try this?
你试过这个吗?
ptr = const_cast<int *>(ptr_to_a);
That should help it compile but it's not really by accident due to the cast.
这应该有助于它编译,但由于演员阵容,这并不是偶然的。
回答by Mithilesh
In C++, Using Microsoft Visual Studio-2008
在 C++ 中,使用 Microsoft Visual Studio-2008
const int a = 3; /* I promisse i won't change a */
int * ptr1 = const_cast<int*> (&a);
*ptr1 = 5; /* I'm a liar, a is now 5 . It's not okay. */
cout << "a = " << a << "\n"; /* prints 3 */
int arr1[a]; /* arr1 is an array of 3 ints */
int temp = 2;
/* or, const volatile int temp = 2; */
const int b = temp + 1; /* I promisse i won't change b */
int * ptr2 = const_cast<int*> (&b);
*ptr2 = 5; /* I'm a liar, b is now 5 . It's okay. */
cout << "b = " << b << "\n"; /* prints 5 */
//int arr2[b]; /* Compilation error */
In C, a const variable can be modified through its pointer; however it is undefined behavior. A const variable can be never used as length in an array declaration.
在 C 中,可以通过其指针修改 const 变量;然而,这是未定义的行为。const 变量永远不能用作数组声明中的长度。
In C++, if a const variable is initialized with a pure constant expression, then its value cannot be modified through its pointer even after try to modify, otherwise a const variable can be modified through its pointer.
在C++中,如果一个const变量用纯常量表达式初始化,那么即使尝试修改后也不能通过其指针修改其值,否则可以通过其指针修改const变量。
A pure integral const variable can be used as length in an array declaration, if its value is greater than 0.
纯整数 const 变量可以用作数组声明中的长度,如果其值大于 0。
A pure constant expression consists of the following operands.
纯常量表达式由以下操作数组成。
A numeric literal (constant ) e.g. 2, 10.53
A symbolic constant defined by #define directive
An Enumeration constant
A pure const variable i.e. a const variable which is itself initialized with a pure constant expression.
Non-const variables or volatile variables are not allowed.
数字文字(常量),例如 2, 10.53
#define 指令定义的符号常量
枚举常量
纯常量变量,即本身用纯常量表达式初始化的常量变量。
不允许使用非常量变量或 volatile 变量。
回答by CompuPlanet
I was looking on how to convert between consts and I found this one http://www.possibility.com/Cpp/const.htmlmaybe it can be useful to someone. :)
我正在研究如何在常量之间进行转换,我发现这个http://www.possibility.com/Cpp/const.html也许它对某人有用。:)
回答by hkBattousai
I have tested the code below and it successfully changes the constant member variables.
我已经测试了下面的代码,它成功地更改了常量成员变量。
#include <iostream>
class A
{
private:
int * pc1; // These must stay on the top of the constant member variables.
int * pc2; // Because, they must be initialized first
int * pc3; // in the constructor initialization list.
public:
A() : c1(0), c2(0), c3(0), v1(0), v2(0), v3(0) {}
A(const A & other)
: pc1 (const_cast<int*>(&other.c1)),
pc2 (const_cast<int*>(&other.c2)),
pc3 (const_cast<int*>(&other.c3)),
c1 (*pc1),
c2 (*pc2),
c3 (*pc3),
v1 (other.v1),
v2 (other.v2),
v3 (other.v3)
{
}
A(int c11, int c22, int c33, int v11, int v22, int v33) : c1(c11), c2(c22), c3(c33), v1(v11), v2(v22), v3(v33)
{
}
const A & operator=(const A & Rhs)
{
pc1 = const_cast<int*>(&c1);
pc2 = const_cast<int*>(&c2),
pc3 = const_cast<int*>(&c3),
*pc1 = *const_cast<int*>(&Rhs.c1);
*pc2 = *const_cast<int*>(&Rhs.c2);
*pc3 = *const_cast<int*>(&Rhs.c3);
v1 = Rhs.v1;
v2 = Rhs.v2;
v3 = Rhs.v3;
return *this;
}
const int c1;
const int c2;
const int c3;
int v1;
int v2;
int v3;
};
std::wostream & operator<<(std::wostream & os, const A & a)
{
os << a.c1 << '\t' << a.c2 << '\t' << a.c3 << '\t' << a.v1 << '\t' << a.v2 << '\t' << a.v3 << std::endl;
return os;
}
int wmain(int argc, wchar_t *argv[], wchar_t *envp[])
{
A ObjA(10, 20, 30, 11, 22, 33);
A ObjB(40, 50, 60, 44, 55, 66);
A ObjC(70, 80, 90, 77, 88, 99);
A ObjD(ObjA);
ObjB = ObjC;
std::wcout << ObjA << ObjB << ObjC << ObjD;
system("pause");
return 0;
}
The console output is:
控制台输出是:
10 20 30 11 22 33
70 80 90 77 88 99
70 80 90 77 88 99
10 20 30 11 22 33
Press any key to continue . . .
Here, the handicap is, you have to define as many pointers as number of constant member variables you have.
这里的障碍是,您必须定义与您拥有的常量成员变量数量一样多的指针。
回答by joexxxz
this will create a runtime fault. Because the intis static. Unhandled exception. Access violation writing location 0x00035834.
这将创建运行时错误。因为int是static。未处理的异常。访问冲突写入位置 0x00035834。
void main(void)
{
static const int x = 5;
int *p = (int *)x;
*p = 99; //here it will trigger the fault at run time
}
回答by joexxxz
You probably want to use const_cast:
您可能想使用 const_cast:
int *ptr = const_cast<int*>(ptr_to_a);
I'm not 100% certain this will work though, I'm a bit rusty at C/C++ :-)
我不是 100% 确定这会起作用,我对 C/C++ 有点生疏:-)
Some readup for const_cast: http://msdn.microsoft.com/en-us/library/bz6at95h(VS.80).aspx
const_cast 的一些读物:http: //msdn.microsoft.com/en-us/library/bz6at95h(VS.80) .aspx