我有一篇文章,但我输了。它展示并描述了一些人们应该小心的C / C ++技巧。其中一个人对我感兴趣,但现在我正在尝试复制它,我无法将其编译。
这个概念是可以在C / C ++中偶然改变const
的值
这是这样的:
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
我想向朋友展示这个,但现在我错过了一步。有谁知道它开始编译和工作缺少什么?
ATM我正在从'const int *'到'int *'的无效转换,但是当我读到我试过的文章时,它运行得很好。
答案 0 :(得分:37)
你需要抛弃常量:
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
此常见答案在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 ..这绝不推荐......我发现g ++不允许这种情况发生..所以这可能是你遇到的问题。
答案 1 :(得分:12)
只是一个猜测,但一个常见的问题是为什么我们无法将int**
转换为const int**
,这看起来是合理的(毕竟,你只是添加一个{ {1}},通常没问题。原因是如果你可以这样做,你可能会意外地修改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
对象(注意没有类型转换)的唯一方法是使第3行成为错误。
您只能在第一级间接时添加const
而无需投射:
const
在C ++中,如果不使用某种类型的类型转换,就不可能修改int * const *ppx = &px; // this is ok
*ppx = &x; // but now this is an error because *ppx is 'const'
对象。您必须使用C风格的演员表或C ++风格的const
来删除const_cast
- ness。任何其他尝试都会导致编译器错误。
答案 2 :(得分:9)
注意标准未定义任何抛弃constness的尝试。从标准的7.1.5.1开始:
除了声明任何类成员 mutable可以修改,任何 尝试修改const对象 在其一生中 导致未定义的行为。
在使用此示例之后:
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
因此,简而言之,使用标准C ++无法实现您的目标。
此外,当编译器遇到类似
的声明时const int a = 3; // I promisse i won't change a
可以自由地将任何出现的'a'替换为3(实际上与#define a 3
做同样的事情)
答案 3 :(得分:7)
回到时间的迷雾中,我们古代程序员使用FORTRAN。 FORTRAN通过引用传递了所有参数,并没有进行任何类型检查。这意味着很容易意外地改变甚至是文字常量的值。你可以将“3”传递给SUBROUTINE,然后它会改变,所以每次你的代码都有一个“3”时,它实际上就像一个不同的值。让我告诉你,这些都是难以找到并修复的错误。
答案 4 :(得分:4)
你试过这个吗?
ptr = const_cast<int *>(ptr_to_a);
这应该有助于它编译,但由于演员而不是偶然的。
答案 5 :(得分:2)
在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 */
在C中,可以通过指针修改const变量;但它是未定义的行为。 const变量永远不能用作数组声明中的长度。
在C ++中,如果使用纯常量表达式初始化const变量,则即使在尝试修改后也无法通过其指针修改其值,否则可以通过其指针修改const变量。
纯积分const变量可以在数组声明中用作长度,如果它的值大于0。
纯常量表达式由以下操作数组成。
数字文字(常量),例如2,10.53
由#define指令定义的符号常量
枚举常量
一个纯const变量,即一个const变量,它本身用纯常量表达式初始化。
不允许使用非常量变量或易变量。
答案 6 :(得分:0)
您正在查看的文章可能一直在谈论
之间的区别const int *pciCantChangeTarget;
const int ci = 37;
pciCantChangeTarget = &ci; // works fine
*pciCantChangeTarget = 3; // compile error
和
int nFirst = 1;
int const *cpiCantChangePointerValue = &nFirst;
int nSecond = 968;
*pciCantChangePointerValue = 402; // works
cpiCantChangePointerValue = &ci; // compile error
或者我记得 - 我这里没有任何东西,只有Java工具,所以无法测试:)。
答案 7 :(得分:0)
最终解决方案:它将const
变量更改为一个值;
cont int a = 10;
*(int*)&a= 5; // now a prints 5
// works fine.
答案 8 :(得分:0)
这将创建运行时故障。因为 int 是静态。未处理的异常。访问冲突写入位置0x00035834。
void main(void)
{
static const int x = 5;
int *p = (int *)x;
*p = 99; //here it will trigger the fault at run time
}
答案 9 :(得分:0)
我测试了下面的代码,它成功地更改了常量成员变量。
#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;
}
控制台输出是:
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 . . .
这里有一个障碍,你必须定义与你拥有的常数成员变量数一样多的指针。
答案 10 :(得分:0)
我正在寻找如何在争论之间进行转换,我发现了这个http://www.possibility.com/Cpp/const.html可能对某人有用。 :)
答案 11 :(得分:0)
我们可以通过以下代码更改const变量值:
const int x=5;
printf("\nValue of x=%d",x);
*(int *)&x=7;
printf("\nNew value of x=%d",x);
答案 12 :(得分:0)
#include<iostream>
int main( void )
{
int i = 3;
const int *pi = &i;
int *pj = (int*)&i;
*pj = 4;
getchar();
return 0;
}
答案 13 :(得分:0)
其中一些答案指出编译器可以优化掉变量'a',因为它被声明为const
。如果您确实希望能够更改a
的值,则需要将其标记为volatile
const volatile int a = 3; // I promise i won't change a
int *ptr = (int *)&a;
(*ptr) = 5; // I'm a liar, a is now 5
当然,将某些内容声明为const volatile
应该真正说明这是多么愚蠢。
答案 14 :(得分:0)
const int foo = 42;
const int *pfoo = &foo;
const void *t = pfoo;
void *s = &t; // pointer to pointer to int
int **z = (int **)s; // pointer to int
**z = 0;
答案 15 :(得分:0)
您可能想要使用const_cast:
int *ptr = const_cast<int*>(ptr_to_a);
我不是100%肯定这会起作用,我在C / C ++上有点生疏: - )
const_cast的一些读取:http://msdn.microsoft.com/en-us/library/bz6at95h(VS.80).aspx
答案 16 :(得分:-2)
您缺少的步骤是您不需要int *指针。这一行:
const int *ptr_to_a = &a; // I still promiss i won't change a;
实际上说你不会改变ptr_to_a,而不是改变。因此,如果您将代码更改为以下内容:
const int a = 3; // I promise I won't change a
const int *ptr_to_a = &a; // I promise I won't change ptr_to_a, not a.
(*ptr_to_a) = 5; // a is now 5
a现在是5.你可以在没有任何警告的情况下通过ptr_to_a进行更改。
编辑:
以上是不正确的。事实证明,我使用shared_ptr混淆了一个类似的技巧,你可以在其中访问原始指针并修改内部数据值,而不会触发任何警告。那就是:
#include <iostream>
#include <boost/shared_ptr.hpp>
int main()
{
const boost::shared_ptr<int>* a = new boost::shared_ptr<int>(new int(3));
*(a->get()) = 5;
std::cout << "A is: " << *(a->get()) << std::endl;
return 0;
}
将产生5。