C / C ++ изменяет значение const - PullRequest
       20

C / C ++ изменяет значение const

18 голосов
/ 24 февраля 2009

У меня была статья, но я ее потерял. Он показал и описал пару приемов C / C ++, что люди должны быть осторожны. Один из них меня заинтересовал, но теперь, когда я пытаюсь воспроизвести его, я не могу его скомпилировать.

Концепция заключалась в том, что можно случайно изменить значение const в C / C ++

Это было примерно так:

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 *' , но когда я прочитал статью, я попытался, и она отлично работала.

Ответы [ 17 ]

38 голосов
/ 24 февраля 2009

вам нужно отбросить постоянство:

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 ++ не позволяет этому случиться ... так что это может быть проблемой, с которой вы столкнулись.

12 голосов
/ 24 февраля 2009

Просто предположение, но общий вопрос - почему нельзя преобразовать 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 без использования какой-либо обработки типов. Вам придется использовать приведение в стиле C или стиль C ++ const_cast, чтобы удалить const -ness. Любая другая попытка сделать это приведет к ошибке компилятора.

9 голосов
/ 24 февраля 2009

Обратите внимание, что любая попытка выбросить константу не определена стандартом. С 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)

7 голосов
/ 24 февраля 2009

В глубине веков мы, палеопрограммисты, использовали FORTRAN. FORTRAN передал все свои параметры по ссылке и не проверял их. Это означало, что было довольно легко случайно изменить значение даже буквальной константы. Вы можете передать «3» подпрограмме, и она вернется, изменившись, и поэтому каждый раз, когда ваш код имеет «3», он будет действовать как другое значение. Позвольте мне сказать вам, что это были серьезные ошибки, чтобы найти и исправить.

4 голосов
/ 24 февраля 2009

Вы пробовали это?

ptr = const_cast<int *>(ptr_to_a);

Это должно помочь компиляции, но это не случайно из-за приведения.

2 голосов
/ 19 апреля 2012

В 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. Чистая константная переменная, то есть константная переменная, которая сама инициализируется чистым константным выражением.

  5. Неконстантные переменные или переменные не допускаются.

0 голосов
/ 18 ноября 2015

Я протестировал приведенный ниже код, и он успешно изменяет постоянные переменные-члены.

#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 голосов
/ 02 января 2015

Я искал, как конвертировать между консолами, и нашел это http://www.possibility.com/Cpp/const.html, возможно, это может быть кому-то полезно :)

0 голосов
/ 11 марта 2013

мы можем изменить значение переменной const следующим кодом:

const int x=5; 

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

*(int *)&x=7;

printf("\nNew value of x=%d",x);
0 голосов
/ 27 ноября 2009
#include<iostream>
int main( void )
{
   int i = 3;    
   const int *pi = &i;
   int *pj = (int*)&i;
    *pj = 4;

   getchar(); 
   return 0;  
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...