Je me demandais s’il y avait un moyen de protéger une variable pour la modifier une fois initialisée (quelque chose comme “constantize” une variable à l’exécution) Par exemple:
#include #include int main(void) { int v, op; scanf( "%d", &op ); if( op == 0 ) v = 1; else v = 2; // here transform v to a constant... . . // ...and that any attempt to modify v yields to an error. . . return EXIT_SUCCESS; }
Vous pouvez faire en sorte que le résultat de l’entrée soit const
comme ceci:
int func() { int op = 0; scanf( "%d", &op ); if( op == 0 ) return 1; else return 2; } int main() { const int v = func(); // ... }
NB Bien sûr, il n’ya aucun moyen d’empêcher que des comportements non définis se produisent plus tard dans le programme, ce qui semble changer v
(étant donné que les comportements non définis peuvent, par définition, avoir un effet quelconque).
Oui: Factor votre code:
foo.h:
void do_something(int arg);
foo.c:
#include "foo.h" void do_something(int arg) { // implement // // Here "arg" is completely under your control. }
foo_test.c:
#include "foo.h" // add unit tests for do_something
principal c:
#include #include #include "foo.h" int main(void) { int op; if (scanf("%d", &op) != 1) { abort(); } do_something(op == 0 ? 1 : 2); }
Le code do_something
clairement que l’argument de fonction de do_something
est privé et local pour la fonction et qu’il ne peut être affecté par rien au-dessus de l’appel.
Le seul moyen d’empêcher une variable globale d’être modifiée après l’initialisation est de la déclarer const
:
const int i = 5;
Toutefois, comme indiqué ci-dessus, cela nécessite qu’il soit initialisé avec la définition. Il n’y a aucun moyen de l’initialiser à partir du code du programme ou en utilisant autre chose qu’une expression constante évaluée au moment de la compilation.
Notez que bien que vous puissiez rejeter le paramètre const, cela entraîne un comportement non défini et très probablement des problèmes car les variables const
peuvent être placées dans une zone de mémoire en lecture seule de votre programme.
Si vous avez besoin de contrôler l’access à une telle variable, vous devrez la placer soit sous forme static
dans une fonction (avec initialisation au premier appel), soit – mieux qu’un module / unité de compilation séparé (également sous forme static
). Utilisez explicitement la fonction setter / getter sur ceci:
"wrapper.h": #ifndef WRAPPER_H #define WRAPPER_H extern void set_once(int v); extern int get_value(void); #endif
"wrapper.c": #include #include "wrapper.h" static struct { bool is_set; // guaranteed false on startup int value; } my_var; void set_once(int v) { if ( !my_var.is_set ) my_var.value = v; else ; // report an error, eg abort() } int get_value(void) { if ( !my_var.is_set ) return my_var.value; // report an error, eg abort() }
"main.c" #include "wrapper.h" int main(void) { set_once(5); int i = get_value(); }
De cette façon, vous pouvez obtenir une erreur d’exécution si vous utilisez la valeur non initialisée ou essayez de la définir plusieurs fois. Notez que l’indicateur repose sur les variables globales à initialiser à 0 (ce qui garantit une évaluation false
). Bien que vous puissiez simplement ignorer plusieurs ensembles, il est recommandé d’attraper et de signaler, au moins pendant le débogage / le test (par exemple, en utilisant assert
).
Modifier:
L’approche ci-dessus concerne les variables globales. Si plusieurs variables doivent être protégées, il est possible de le modifier, par exemple, les fonctions prennent un pointeur sur la structure. Si différents types doivent être utilisés, comstackz l’indicateur dans sa propre structure et ajoutez-le comme premier champ anonyme à un type de structure pour chaque type à protéger. Si les extensions gcc sont disponibles et autorisées, jetez un œil à -fplan9-extensions
. L’utilisation de pointeurs opaques permet d’éviter des modifications externes involontaires.
Pour les variables locales, toutefois, utilisez la version de @ MattMcNabb.
Non jamais.
Vous pouvez le rendre const
, mais c’est un léger indice et vous pouvez le jeter avec presque aucun effort. De plus, si vous avez un pointeur sur quelque chose, vous pouvez toujours le changer par access direct à la mémoire.
Vous pouvez également le masquer dans une classe qui gère l’access en écriture à celle-ci, mais vous vous trouvez dans la même situation que dans le premier cas: vous avez un pointeur sur celle-ci.