web-dev-qa-db-fra.com

Peut-on changer la valeur d'un objet défini avec const via des pointeurs?

#include <stdio.h>
int main()
{
    const int a = 12;
    int *p;
    p = &a;
    *p = 70;
}

Est-ce que ça marchera?

26
Shweta

Il s'agit d'un "comportement non défini", ce qui signifie que, sur la base de cette norme, vous ne pouvez pas prédire ce qui se passera si vous essayez ceci. Il peut faire différentes choses selon la machine, le compilateur et l'état du programme.

Dans ce cas, le plus souvent, c’est que la réponse sera "oui". Une variable, constante ou non, est simplement un emplacement en mémoire, vous pouvez enfreindre les règles de constance et simplement l'écraser. (Bien sûr, cela causera un bug grave si une autre partie du programme dépend de la constance de ses données const!)

Toutefois, dans certains cas - le plus souvent pour des données const static -, le compilateur peut placer ces variables dans une région de mémoire en lecture seule. MSVC, par exemple, place généralement des entrées statiques constantes dans le segment .text de l'exécutable, ce qui signifie que le système d'exploitation génère une erreur de protection si vous essayez d'écrire dessus et que le programme se bloque.

Dans une autre combinaison de compilateur et de machine, quelque chose de totalement différent peut se produire. La seule chose que vous pouvez prédisez avec certitude est que ce modèle va gêner quiconque doit lire votre code.

30
Crashworks

C'est un comportement indéfini. Preuve:

/* program.c */

int main()
{
        const int a = 12;
        int* p;
        p = &a;
        *p = 70;
        printf("%d\n", a);
        return 0;
}


gcc program.c

et l'exécuter. La sortie sera 70 (gcc 4.3)

Puis compilez-le comme ceci:

gcc -O2 program.c

et l'exécuter. La sortie sera de 12. Lorsque l'optimisation est faite, le compilateur charge probablement 12 dans un registre et ne se charge pas de le charger à nouveau lorsqu'il doit accéder à a pour le printf car il "sait" qu'il ne peut pas changer.

13
JeremyP

La modification d'un objet qualifié const par le biais d'un pointeur appelle un comportement indéfini, tel est le résultat. C'est probablement quelque chose que vous attendez cependant, à savoir. la valeur précédente reste inchangée, si elle a été placée dans .text, etc.

10
Michael Foukarakis

Cela fonctionne bien avec gcc. Cela ne l'a pas aimé cependant:

test.c: 6: warning: l'affectation supprime les qualificateurs du type de cible du pointeur

Mais la valeur a changé lors de l'exécution. Je ne soulignerai pas l'évident non-non ...

5
Alexander Sagen

oui, vous pouvez le faire en utilisant un tel code. mais le code ne s'applique pas lorsque a est global (un programme compilé par gcc m'a donné segmentation fault.)

de manière générale, dans votre C bien-aimé, vous pouvez presque toujours trouver un moyen de pirater des choses qui ne sont pas supposées être modifiées ou exposées. const ici étant un exemple.

Mais penser au pauvre type (peut-être moi-même après 6 mois) maintient notre code, je choisis souvent de ne pas le faire.

3
Jokester

Ici, le type de pointeur p est int*, auquel est attribuée la valeur de type const int* (&a => adresse d'une variable const int). 

La distribution implicite élimine la constance, bien que gcc envoie un avertissement (veuillez noter que cela dépend en grande partie de la mise en œuvre).

Étant donné que le pointeur n'est pas déclaré en tant que const, la valeur peut être modifiée à l'aide d'un tel pointeur.

si le pointeur devait être déclaré en tant que const int* p = &a, vous ne pourrez pas faire *p = 70

1
Hemant

Vous ne pouvez pas modifier la valeur d'une variable constante à l'aide d'un pointeur pointant vers elle. Ce type de pointeur s'appelle Pointer to a constant.

Il existe également un autre concept appelé Constant Pointer. Cela signifie qu'une fois qu'un pointeur pointe vers un emplacement de mémoire, vous ne pouvez pas le faire pointer vers un autre emplacement.

0
Abhijeet Pathak

Mauvaise idée.

En outre, le comportement est spécifique à la plate-forme et à la mise en œuvre. Si vous utilisez une plate-forme où la constante est stockée dans une mémoire non inscriptible, cela ne fonctionnera évidemment pas.

Et pourquoi voudriez-vous le faire? Mettez à jour la constante dans votre source ou faites-en une variable.

0
3Dave

Ce code contient une violation de contrainte :

const int a = 12;
int *p;
p = &a;

La contrainte violée est C11 6.5.16.1/1 "Affectation simple"; Si les deux opérandes sont des pointeurs, le type pointé par la gauche doit avoir tous les qualificateurs du type pointé par la droite. (Et les types, sans qualificatifs, doivent être compatibles).

Donc, la contrainte est violée parce que &a a le type const int *, qui a const comme qualificatif; mais ce qualificatif n'apparaît pas dans le type de p qui est int *.

Le compilateur doit émettre un diagnostic et ne pas générer d’exécutable. Le comportement de tout exécutable serait complètement indéfini, car le programme ne respecte pas les règles du langage.

0
M.M