記事はありましたが、失くしました。人々が注意すべきいくつかのC/C++トリックを示し、説明しました。それらの1つは私に興味を示しましたが、今はそれを複製しようとしているので、コンパイルすることができません。
概念は、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
オブジェクトを変更してしまう可能性があるためです。
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
オブジェクトを変更できないことを確認する唯一の方法(型キャストがないことに注意してください)は、3行目をエラーにすることです。
const
の追加は、間接参照の最初のレベルでのキャストなしでのみ許可されています。
int * const *ppx = &px; // this is ok
*ppx = &x; // but now this is an error because *ppx is 'const'
C++では、なんらかの型キャストを使用せずにconst
オブジェクトを変更することはできません。 const
- nessを削除するには、CスタイルのキャストまたはC++スタイルのconst_cast
を使用する必要があります。これを実行しようとすると、どこかでコンパイラエラーが発生します。
定数を捨て去ろうとする試みは標準では定義されていないことに注意してください。標準の7.1.5.1から:
変更可能と宣言されたクラスメンバーは変更できることを除いて、存続期間中に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
と同じことを効果的に行う)
時の流れに戻ると、私たちは古プログラマーがFORTRANを使用していました。 FORTRANはすべてのパラメーターを参照で渡し、型チェックは行いませんでした。つまり、リテラル定数であっても、誤って値を変更してしまうことは非常に簡単でした。 SUBROUTINEに「3」を渡すと、変更されて戻ってきます。そのため、それ以降、コードに「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変数はポインターを介して変更できます。
純粋な整数のconst変数は、その値が0より大きい場合、配列宣言で長さとして使用できます。
純粋な定数式は、次のオペランドで構成されます。
数値リテラル(定数)。 2、10.53
#defineディレクティブで定義された記号定数
列挙定数
純粋なconst変数、つまり、それ自体が純粋な定数式で初期化されるconst変数。
非const変数またはvolatile変数は使用できません。
あなたが見ていた記事は違いを話しているかもしれません
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ツールがここにあるので、テストできないので、他に何もありません:)
私はconst間で変換する方法を探していましたが、これを見つけました http://www.possibility.com/Cpp/const.html 多分それは誰かにとって役立つかもしれません。 :)
最終的な解決策:const
変数の値を変更します。
cont int a = 10;
*(int*)&a= 5; // now a prints 5
// works fine.
これらの回答のいくつかは、const
と宣言されているので、コンパイラーが変数 'a'を最適化できることを指摘しています。 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
として宣言すると、これがどれほど愚かであるかを実際に示す必要があります。
#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;
}
これにより、ランタイムエラーが発生します。 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 <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 . . .
ここでのハンディキャップは、定数メンバー変数の数と同じ数のポインターを定義する必要があることです。
次のコードで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_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;