21

記事がありましたが、紛失してしまいました。注意が必要な C/C++ のトリックをいくつか示し、説明しました。そのうちの 1 つに興味がありましたが、複製しようとしている今、コンパイルすることができません。

const概念は、C/C++で a の値を誤って変更する可能性があるというものでした。

それは次のようなものでした:

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*' への無効な変換が発生していますが、記事を読んで試してみたところ、うまくいきました。

4

18 に答える 18

44

あなたは恒常性を捨てる必要があります:

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++がこれを起こさせないことを発見しました..それはあなたが経験している問題かもしれません。

于 2009-02-24T19:02:12.900 に答える
12

constness をキャストしようとする試みは、標準では定義されていないことに注意してください。標準の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)

于 2009-02-24T19:17:05.233 に答える
12

単なる推測ですが、よくある質問は、なぜ anint**を aconst 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

これは非常に非直感的な結果ですがconst、この場合にオブジェクトを変更できないことを確認する唯一の方法 (型キャストがないことに注意してください) は、3 行目をエラーにすることです。

const間接化の FIRST レベルでキャストなしでのみ追加できます。

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

constC++ では、ある種の型キャストを使用せずにオブジェクトを変更することはできません。-nessconst_castを削除するには、C スタイルのキャストまたは C++ スタイルのいずれかを使用する必要があります。constそれ以外の試みを行うと、どこかでコンパイラ エラーが発生します。

于 2009-02-24T19:19:03.873 に答える
9

むかしむかし、私たちパレオ プログラマーは FORTRAN を使用していました。FORTRAN はすべてのパラメータを参照渡しし、型チェックを一切行いませんでした。これは、リテラル定数の値であっても、誤って変更することが非常に簡単であることを意味していました。「3」をサブルーチンに渡すと、それが変更されて返されるため、それ以降はコードに「3」が含まれるたびに、実際には異なる値のように動作します。これらは見つけて修正するのが難しいバグでした。

于 2009-02-24T19:13:18.583 に答える
4

これを試しましたか?

ptr = const_cast<int *>(ptr_to_a);

それはコンパイルに役立つはずですが、キャストによる偶然ではありません。

于 2009-02-24T18:58:18.383 に答える
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 より大きい場合、配列宣言で長さとして使用できます。

純粋な定数式は、次のオペランドで構成されます。

  1. 数値リテラル (定数) 例: 2、10.53

  2. #define 指令で定義された記号定数

  3. 列挙定数

  4. 純粋な const 変数、つまり、それ自体が純粋な定数式で初期化される const 変数。

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

于 2012-04-19T06:43:30.513 に答える
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

于 2009-02-24T18:58:58.787 に答える
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
}
于 2016-04-12T20:18:28.053 に答える
0

これらの回答のいくつかは、変数「a」が宣言されているため、コンパイラが変数「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

もちろん、何かを as と宣言することは、const volatileこれがいかにばかげているかを実際に示しているはずです。

于 2009-02-24T20:35:30.647 に答える
0

const 間で変換する方法を探していたところ、これが見つかりましたhttp://www.possibility.com/Cpp/const.html誰かにとって役立つかもしれません。:)

于 2015-01-02T10:10:17.530 に答える
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;
于 2009-02-24T19:10:33.440 に答える
0
#include<iostream>
int main( void )
{
   int i = 3;    
   const int *pi = &i;
   int *pj = (int*)&i;
    *pj = 4;

   getchar(); 
   return 0;  
}
于 2009-11-27T05:58:58.680 に答える
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 . . .

ここで、ハンディキャップは、定数メンバー変数の数と同じ数のポインターを定義する必要があることです。

于 2015-11-18T09:07:36.320 に答える
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ツールしかないので、テストできません:)

于 2009-02-24T19:24:06.543 に答える
-1

次のコードで const 変数の値を変更できます。

const int x=5; 

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

*(int *)&x=7;

printf("\nNew value of x=%d",x);
于 2013-03-11T10:43:53.080 に答える
-1
#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;
}
于 2018-09-15T07:25:07.667 に答える
-2

あなたが見逃しているステップは、 int* ポインターが必要ないということです。この線:

const int *ptr_to_a = &a; // I still promiss i won't change a;

実際には、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 になりました。警告なしで a から 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個製作します。

于 2009-02-24T19:12:16.027 に答える