web-dev-qa-db-fra.com

C/C++ changer la valeur d'un const

J'ai eu un article, mais je l'ai perdu. Il a montré et décrit quelques astuces de C/C++ que les gens devraient faire attention. L'un d'entre eux m'a intéressé, mais maintenant que j'essaie de le reproduire, je ne suis pas en mesure de le compiler.

Le concept était qu'il est possible de changer accidentellement la valeur de const en C/C++

C'était quelque chose comme ç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

Je voulais montrer cela à un ami mais maintenant il me manque une étape. Est-ce que quelqu'un sait ce qui manque pour qu'il commence à compiler et à travailler?

ATM je reçois une conversion non valide de 'const int *' à 'int *' mais lorsque j'ai lu l'article, j'ai essayé et cela a très bien fonctionné.

17
fmsf

vous devez rejeter la constance:

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

aussi la réponse commune ne fonctionne pas dans 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 ~ $

bTW .. ce n'est jamais recommandé ... J'ai trouvé que g ++ ne permet pas que cela se produise .. de sorte que peut-être le problème que vous rencontrez.

37
sfossen

Juste une supposition, mais une question commune est pourquoi on ne peut pas convertir un int** en un const int**, ce qui au premier abord semble être raisonnable (après tout, vous ajoutez simplement une const, ce qui est normalement correct). La raison en est que si vous pouviez le faire, vous pourriez accidentellement modifier un objet 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

C'est un résultat très peu intuitif, mais le seul moyen de vous assurer que vous ne pouvez pas modifier un objet const dans ce cas (remarquez qu'il n'y a pas de typecasts) est de faire de la ligne 3 une erreur.

Vous êtes uniquement autorisé à ajouter const sans conversion au PREMIER niveau d'indirection:

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

En C++, il est impossible de modifier un objet const sans utiliser une conversion de type. Vous devrez utiliser un transtypage de style C ou un const_cast de style C++ pour supprimer la const- ness. Toute autre tentative dans ce sens entraînera une erreur du compilateur quelque part.

12
Adam Rosenfield

Notez que toute tentative de rejeter la constance n’est pas définie par la norme. À partir de 7.1.5.1 de la norme:

Sauf que tout membre du groupe déclaré que Peut être modifié peut être modifié, toute Tentative de modification d'un objet const Au cours de sa vie Entraîne un comportement indéfini.

Et juste après cet exemple est utilisé:

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

En bref, ce que vous voulez faire n’est pas possible avec le C++ standard.

De plus quand le compilateur rencontre une déclaration comme

const int a = 3; // I promisse i won't change a

il est libre de remplacer n'importe quelle occurrence de 'a' par 3 (en réalité, faire la même chose que #define a 3)

8
Andrew Khosravian

Dans la nuit des temps, nous, paleo-programmeurs, utilisions le Fortran. FORTRAN a passé tous ses paramètres par référence et n'a procédé à aucun contrôle de frappe. Cela signifiait qu'il était assez facile de changer accidentellement la valeur d'une constante même littérale. Vous pouvez passer "3" à une SUBROUTINE, qui reviendrait changée. Ainsi, chaque fois que votre code contient un "3", il agit en réalité comme une valeur différente. Laissez-moi vous dire que c'étaient des bugs difficiles à trouver et à corriger.

7
Paul Tomblin

Avez-vous essayé cela?

ptr = const_cast<int *>(ptr_to_a);

Cela devrait aider à la compilation mais ce n’est pas vraiment accidentel à cause du casting.

4
Michael Kristofik

En C++, utilisation de 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 */

En C, une variable const peut être modifiée via son pointeur; Cependant, il s'agit d'un comportement indéfini. Une variable const ne peut jamais être utilisée comme longueur dans une déclaration de tableau.

En C++, si une variable const est initialisée avec une expression constante pure, sa valeur ne peut pas être modifiée via son pointeur même après une tentative de modification, sinon une variable const peut être modifiée via son pointeur.

Une variable intégrale pure pure peut être utilisée comme longueur dans une déclaration de tableau, si sa valeur est supérieure à 0.

Une expression constante pure comprend les opérandes suivants.

  1. Un littéral numérique (constant), par ex. 2, 10,53 

  2. Une constante symbolique définie par la directive #define

  3. Une constante d'énumération

  4. Une variable const pure, c’est-à-dire une variable const qui est elle-même initialisée avec une expression constante pure.

  5. Les variables non constantes ou volatiles ne sont pas autorisées.

2
Mithilesh

L’article que vous avez examiné aurait peut-être parlé de la différence entre

const int *pciCantChangeTarget;
const int ci = 37;
pciCantChangeTarget = &ci; // works fine
*pciCantChangeTarget = 3; // compile error

et

int nFirst = 1;
int const *cpiCantChangePointerValue = &nFirst;
int nSecond = 968;

*pciCantChangePointerValue = 402; // works
cpiCantChangePointerValue = &ci; // compile error

Ou alors je me souviens-- je n'ai rien d'autre que des outils Java ici, donc je ne peux pas tester :)

0
mjfgates

Je cherchais comment convertir des consts et j’ai trouvé celui-ci http://www.possibility.com/Cpp/const.html peut-être que cela peut être utile à quelqu'un. :)

0
CompuPlanet

Certaines de ces réponses indiquent que le compilateur peut optimiser la variable 'a' puisqu'elle est déclarée const. Si vous voulez vraiment pouvoir changer la valeur de a, vous devez le marquer comme 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

Bien sûr, déclarer quelque chose en tant que const volatile devrait vraiment illustrer à quel point c'est idiot.

0
pk.
#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;
}
0
kesarling

cela créera une faute d'exécution. Parce que le int est statique . Exception non-gérée. Emplacement d'écriture de violation d'accès 0x00035834.

void main(void)
{
    static const int x = 5;
    int *p = (int *)x;
    *p = 99;                //here it will trigger the fault at run time
}
0
joexxxz

J'ai testé le code ci-dessous et il change avec succès les variables de membre constant.

#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;
}

La sortie de la console est:

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

Ici, le handicap est que vous devez définir autant de pointeurs que de variables de membre constant.

0
hkBattousai

nous pouvons changer la valeur de la variable const par le code suivant:

const int x=5; 

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

*(int *)&x=7;

printf("\nNew value of x=%d",x);
0
Aryan
#include<iostream>
int main( void )
{
   int i = 3;    
   const int *pi = &i;
   int *pj = (int*)&i;
    *pj = 4;

   getchar(); 
   return 0;  
}
0
manoj

Vous voulez probablement utiliser const_cast:

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

Je ne suis pas sûr à 100% que cela fonctionnera bien, je suis un peu rouillé en C/C++ :-)

Quelques lectures pour const_cast: http://msdn.Microsoft.com/en-us/library/bz6at95h(VS.80).aspx

0
Steffen
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
dirkgently