[英]C/C++ changing the value of a const
我有一篇文章,但我把它弄丟了。 它展示並描述了一些人們應該小心的 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*' 的轉換無效,但是當我閱讀這篇文章時,我嘗試過並且效果很好。
你需要拋棄常量:
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 ~ $
順便說一句..這絕不是推薦的...我發現 g++ 不允許這種情況發生..所以這可能是您遇到的問題。
只是一個猜測,但一個常見的問題是為什么不能將int**
轉換為const int**
,這乍一看似乎是合理的(畢竟,您只是添加一個const
,這通常是可以的) . 原因是如果你可以這樣做,你可能會不小心修改一個const
object:
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
這是一個非常不直觀的結果,但在這種情況下確保您不能修改const
object 的唯一方法(注意如何沒有類型轉換)是使第 3 行出錯。
您只能在 FIRST 間接級別添加const
而不進行強制轉換:
int * const *ppx = &px; // this is ok
*ppx = &x; // but now this is an error because *ppx is 'const'
在 C++ 中,如果不使用某種類型轉換,就不可能修改const
object。 您必須使用 C 風格的強制轉換或 C++ 風格的const_cast
來刪除const
-ness。 任何其他這樣做的嘗試都會在某處導致編譯器錯誤。
請注意,標准未定義任何拋棄 constness 的嘗試。 從標准的 7.1.5.1 開始:
除了可以修改聲明為 mutable 的任何 class 成員之外,任何在其生命周期內修改 const object 的嘗試都會導致未定義的行為。
在使用此示例之后:
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
相同的事情)
回到時間的迷霧中,我們古程序員使用 FORTRAN。 FORTRAN 通過引用傳遞了它的所有參數,並且沒有做任何類型檢查。 這意味着即使是字面常量也很容易意外更改值。 您可以將“3”傳遞給 SUBROUTINE,它會返回更改,因此從那時起,您的代碼每次都有“3”,它實際上就像一個不同的值。 讓我告訴你,這些是很難找到和修復的錯誤。
你試過這個嗎?
ptr = const_cast<int *>(ptr_to_a);
這應該有助於它編譯,但由於演員陣容,這並不是偶然的。
在 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變量。
如果其值大於 0,則純整數 const 變量可用作數組聲明中的長度。
純常量表達式由以下操作數組成。
數字文字(常量),例如 2, 10.53
#define 指令定義的符號常量
枚舉常量
純 const 變量,即本身使用純常量表達式初始化的 const 變量。
不允許使用非常量變量或易失變量。
我們可以通過以下代碼更改 const 變量值:
const int x=5;
printf("\nValue of x=%d",x);
*(int *)&x=7;
printf("\nNew value of x=%d",x);
#include<iostream>
int main( void )
{
int i = 3;
const int *pi = &i;
int *pj = (int*)&i;
*pj = 4;
getchar();
return 0;
}
我正在尋找如何在 const 之間進行轉換,我發現這個http://www.possibility.com/Cpp/const.html也許它對某人有用。 :)
我已經測試了下面的代碼,它成功地更改了常量成員變量。
#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;
}
控制台 output 是:
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 . . .
在這里,障礙是,您必須定義與您擁有的常量成員變量一樣多的指針。
這將產生運行時錯誤。 因為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
}
#include<stdio.h>
#include<stdlib.h>
int main(void) {
const int a = 1; //a is constant
fprintf(stdout,"%d\n",a);//prints 1
int* a_ptr = &a;
*a_ptr = 4;//memory leak in c(value of a changed)
fprintf(stdout,"%d",a);//prints 4
return 0;
}
最終解決方案:它將更改const
變量的值;
cont int a = 10;
*(int*)&a= 5; // now a prints 5
// works fine.
您可能想使用 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
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;
您正在查看的文章可能一直在談論兩者之間的區別
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 工具之外什么都沒有,所以無法測試:)
其中一些答案指出,編譯器可以優化掉變量 '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
應該真正說明這是多么愚蠢。
您缺少的步驟是您不需要 int* 指針。 該行:
const int *ptr_to_a = &a; // I still promiss i won't change a;
實際上說你不會改變ptr_to_a,而不是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 更改 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。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.