2009-02-24 17 views
13

私は記事を持っていましたが、それを失ってしまいました。それは人々が注意するべきであるC/C++トリックのいくつかを示し、記述しました。そのうちの1人は私に興味がありましたが、今私はそれを複製しようとしています。私はそれをコンパイルすることができません。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 *'への変換が無効ですが、記事を読むとうまくいきました。

+0

私は完全なプログラムを投稿し、それがg ++でブロックされていると説明しました.gccはこの動作を許可しています。 – sfossen

+2

コンパイルする場合でも。それは未定義の動作です。あなたのコンピュータを爆破したり、プログラムをクラッシュさせたり、悪魔を鼻から飛ばしたりするかもしれません。もちろん、それは動作するように見えるかもしれません。今のところ。あなたのマシンで。 – jalf

答えて

35

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が++これが起こることはできません見つける... ..これは推奨されることはありません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 ~ $ 

では動作しません。経験している。

+0

が試行されましたが、動作しません:\ aは同じ値を保持し、(* ptr)は別の値を持ちます – fmsf

+0

Macでg ++を使用していますbtw – fmsf

+0

int 4.1.2 gccではなくブロックされています。 – sfossen

4

これを試しましたか?

ptr = const_cast<int *>(ptr_to_a); 

これはコンパイルに役立ちますが、実際にはキャストのために実際には発生しません。

+0

うん、私は知っているが、それはなくてもだと思う。 – fmsf

+0

あなたは正しい答えを得られるように見えるが、const_castのないソリューションが現れた場合には少し長くなるだろう。私は本当にそれが – fmsf

+0

を行うと信じていますこれは間違っています。それが要求された動作を引き起こさないのは – sfossen

0

おそらくはconst_castを使用したい:

int *ptr = const_cast<int*>(ptr_to_a); 

私はC/Cで少しさびたんだ、これはしかし動作する一定の100%ではないよ++ :-)

のためのいくつかのreadupをconst_cast:あなたはconst性を離れてキャストする必要がhttp://msdn.microsoft.com/en-us/library/bz6at95h(VS.80).aspx

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; 
+0

は、コンパイルしても動作しません。fooはまだ42 – fmsf

+0

でコンパイルされていませんか? – dirkgently

+0

VS2005でも終わりました:(gccに手を置く前に待たなければならないでしょう。 – dirkgently

-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 

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

+0

はコンパイルされません。 "エラー:読み取り専用場所の割り当て" – fmsf

+0

いいえ、ptr_to_aはaです。 const intへのポインタ、つまりあなたが変更しないことを約束していることを意味します。 –

+0

ええええええええええええええええええええええええええええええええええええええええええええと、 – jasedit

6

を演出します、我々は古プログラマはFORTRANを使用しました。FORTRANは、すべてのパラメータを参照渡しし、型チェックを行いませんでした。これは、リテラル定数の値を誤って変更することは非常に容易であることを意味していました。あなたはSUBROUTINEに "3"を渡すことができ、それは変更されて戻ってくるでしょうから、あなたのコードに "3"があったときはいつも別の値のように振る舞います。それらは見つけて修正するのが難しいバグでした。

+0

"3"というものが私の一日を作ったのです:) –

8

constをキャストしようとする試みはすべて、標準によって定義されていません。標準の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.

そして右この例の後に使用されています。

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 

のような宣言は、3で「A」のいずれかのoccuranceを置き換えるために自由である(事実#define a 3と同じことをやって)

12

だけの推測が、一般的な質問は、int**const int**に変換できないことです(最初は妥当であると思われます)。通常は大丈夫です(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オブジェクトを変更することができないことを確認する唯一の方法:その理由は、あなたがこれを行うことができれば、あなたが誤ってconstオブジェクトを変更する可能性があることですこの場合(型キャストがないことに注意してください)は、3行目をエラーにすることです。あなたが唯一の間接の第1レベルにキャストせずにconstの追加を許可している

:C++で

int * const *ppx = &px; // this is ok 
*ppx = &x;    // but now this is an error because *ppx is 'const' 

、ある種の型キャストを使用せずにconstオブジェクトを修正することは不可能です。 const -nessを削除するには、CスタイルのキャストまたはC++スタイルのconst_castのいずれかを使用する必要があります。これを行う他の試みはどこかにコンパイラエラーを引き起こすでしょう。

+2

今はいつも、私はこの推論を再び行います。それはいつも私の頭を傷つける。 –

+1

@Michael:phew - 私は一人ではない。あまりにも私のもの! –

0

あなたが見ていた記事では、私がここにJavaツール以外のものを持っていないrecall--

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 

かそこらの違いについて話されている可能性があり、だからテストできません。

-1

これらの回答の中には、constと宣言されているため、コンパイラは変数 'a'を最適化できることを指摘しています。あなたが本当にaの値を変更できるようにしたいなら、あなたはconst volatileが本当にこれがどれだけ愚かな説明すべきであるとして何かを宣言し、もちろん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 

としてそれをマークする必要があります。C++で

+0

私はその言葉(「揮発性」)は、あなたがそれが意味すると思うことを意味するとは思わない。値を変更できるかどうかは関係ありませんが、ソースコードの読み取りまたは書き込みが実行可能ファイル内での読み取りまたは書き込みであることを保証します。つまり、キャッシングはありません。 –

+0

それは私が得ていたものです。コンパイラはconstを見て値を最適化します。一方、あなたがそれが揮発性であると宣言すれば、あなたが 'キャッシングなし'と言ったように、それはできません。 –

+0

これは間違って投票され、ポスターにはポイントがありません。 –

0
#include<iostream> 
int main(void) 
{ 
    int i = 3;  
    const int *pi = &i; 
    int *pj = (int*)&i; 
    *pj = 4; 

    getchar(); 
    return 0; 
} 
2

、Cで

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 */ 

マイクロソフトのVisual Studio 2008を使用して、CONST変数は、そのポインタを介して変更することができます。ただし、未定義の動作です。配列宣言では、const変数を長さとして使用することはできません。

C++では、定数変数が純粋な定数式で初期化されている場合、その値をポインタで変更することはできません。そうしないと、ポインタを介してconst変数を変更できます。その値は、純粋な定数式は、次のオペランドで構成されて0

より大きい場合

純粋積分CONST変数は、配列宣言の長さとして使用することができます。

  1. 数値定数(定数)。 2、

  2. すなわちそれ自体が純粋な定数式で初期化されるCONST変数純粋CONST変数

  3. アン列挙定数#define命令によって定義10.53

  4. 記号定数。

  5. const以外の変数またはvolatile変数は使用できません。

0

我々は次のコードでのconst変数の値を変更することができます。

const int x=5; 

printf("\nValue of x=%d",x); 

*(int *)&x=7; 

printf("\nNew value of x=%d",x); 
+0

「新しい値x = 5」を印刷するときはどうしますか? – MSalters

+0

codepad.orgの出力はx = 5の値です x = 5の新しい値 – Mak

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

、ハンデがある、あなたが持っている一定のメンバ変数の数と同じ数のポインタを定義する必要があります。

0

これにより、ランタイムフォルトが作成されます。 intstaticです。未処理の例外。場所0x00035834のアクセス違反を書き込みます。

void main(void) 
{ 
    static const int x = 5; 
    int *p = (int *)x; 
    *p = 99;    //here it will trigger the fault at run time 
} 
関連する問題