Quel est exactement le danger d'utiliser des valeurs de débogage magiques (comme 0xDEADBEEF) comme littéraux?

StackOverflow https://stackoverflow.com/questions/1681144

Question

Il va sans dire que l'utilisation de pointeurs codé en dur, hexagonaux littéral est une catastrophe:

int *i = 0xDEADBEEF;
// god knows if that location is available

Cependant, comme variable ce qui est exactement le danger en utilisant les littéraux hexagonaux valeurs

int i = 0xDEADBEEF;
// what can go wrong?

Si ces valeurs sont en effet « dangereux » en raison de leur dans divers débogage scénarios , cela signifie que même si je ne l'utilise ces littéraux, tout programme lors de l'exécution arrive de tomber sur une de ces valeurs peut se bloquer.

Quelqu'un veut expliquer les dangers réels de l'utilisation des littéraux hexagonaux?


Modifier juste pour clarifier, je ne parle pas de l'utilisation générale des constantes dans le code source. Je parle spécifiquement de problèmes de débogage des scénarios qui pourraient se présenter à l'utilisation des valeurs hexagonales, avec l'exemple spécifique de 0xDEADBEEF.

Était-ce utile?

La solution

Je crois que la préoccupation soulevée dans l'adresse IP formatage question plus tôt aujourd'hui n'a pas été liée à l'utilisation de littéraux hexagonaux en général, mais l'utilisation spécifique de 0xDEADBEEF. Au moins, c'est la façon dont je l'ai lu.

Il y a un problème avec l'utilisation 0xDEADBEEF en particulier, mais à mon avis, il est un petit. Le problème est que de nombreux débogueurs et systèmes d'exécution ont Coopté déjà cette valeur particulière en tant que valeur de marqueur pour indiquer tas non alloué, mauvais pointeurs sur la pile, etc.

Je ne me souviens pas du haut de ma tête juste que le débogage et les systèmes d'exécution utilisent cette valeur particulière, mais je l'ai vu utilisé de cette façon plusieurs fois au cours des années. Si vous déboguez dans l'un de ces environnements, l'existence de la constante 0xDEADBEEF dans votre code sera impossible à distinguer des valeurs dans la RAM non alloué ou que ce soit, donc, au mieux, vous n'aurez pas aussi utile dépotoirs RAM, et au pire, vous obtiendrez des avertissements à partir du débogueur.

Quoi qu'il en soit, c'est ce que je pense que le commentateur d'origine a voulu dire quand il vous a dit qu'il était mauvais pour « l'utilisation dans divers scénarios de débogage. »

Autres conseils

Il n'y a plus de danger à utiliser un hexagone littéral que tout autre type de littéral.

Si votre session de débogage se termine l'exécution de données sous forme de code sans vous l'intention à, vous êtes dans un monde de la douleur de toute façon.

Bien sûr, il y a la normale « valeur magique » vs odeur « bien nommée constante » code / problème de propreté, mais ce n'est pas vraiment le genre de danger, je pense que vous parlez.

À quelques exceptions près, rien est "constante".

Nous préférons les appeler des « variables lentes » -. Leur valeur change si lentement que ne nous dérange pas recompiler les changer

Cependant, nous ne voulons pas avoir de nombreux cas de 0x07 tout au long d'une application ou un script de test, où chaque instance a un sens différent.

Nous voulons mettre une étiquette sur chaque constante qui le rend totalement sans ambiguïté ce que cela signifie.

if( x == 7 )

Que signifie « 7 » dans la déclaration ci-dessus? Est-ce la même chose que

d = y / 7;

Est-ce le même sens de « 7 »?

Les cas de test sont un problème légèrement différent. On n'a pas besoin vaste, une gestion attentive de chaque instance d'un numérique littéral. Nous avons plutôt besoin de documentation.

On peut - dans une certaine mesure - expliquer d'où vient « 7 » en incluant un petit peu d'un indice dans le code

.
assertEquals( 7, someFunction(3,4), "Expected 7, see paragraph 7 of use case 7" );

Une "constante" doit être déclaré - et nommé -. Exactement une fois

Un « résultat » dans un test unitaire n'est pas la même chose comme une constante, et nécessite un peu de soin pour expliquer d'où il vient.

Un hexagone littéral est pas différent d'un littéral comme 1. décimal une signification particulière d'une valeur est due au contexte d'un programme particulier.

Il n'y a aucune raison pour laquelle vous ne devriez pas attribuer 0xdeadbeef à une variable.

Mais malheur au programmeur qui tente d'attribuer 3735928559 décimal, ou 33653337357 octal, ou pire. 11011110101011011011111011101111 binaire

Big Endian ou Little Endian?

Un danger est quand les constantes sont affectées à un tableau ou une structure avec les différents membres de taille; endian ness du compilateur ou de la machine (y compris machine virtuelle Java vs CLR) auront une incidence sur l'ordre des octets.

Cette question est vrai des valeurs non constantes, aussi, bien sûr.

Voici un, certes artificiel, par exemple. Quelle est la valeur de tampon [0] après la dernière ligne?

const int TEST[] = { 0x01BADA55,  0xDEADBEEF };
char buffer[BUFSZ];

memcpy( buffer, (void*)TEST, sizeof(TEST));

Je ne vois pas de problème avec l'utilisation comme valeur. Son juste un numéro après tout.

Il n'y a pas de danger à l'aide d'une valeur hexadécimale codée en dur pour un pointeur (comme votre premier exemple) dans le bon contexte. En particulier, lorsque vous faites très faible niveau de développement de matériel, ceci est la façon dont vous accédez à des registres mappés en mémoire. (Bien qu'il soit préférable de leur donner des noms avec un #define, par exemple.) Mais au niveau de l'application vous ne devriez pas avoir besoin de faire une mission comme ça.

J'utilise CAFEBABE Je ne l'ai pas vu utilisé par les débogueurs avant.

int *i = 0xDEADBEEF;
// god knows if that location is available

int i = 0xDEADBEEF;
// what can go wrong?

Le danger que je vois est le même dans les deux cas: vous avez créé une valeur de drapeau qui n'a pas de contexte immédiat. Il n'y a rien au sujet i dans les deux cas qui me le faire savoir 100, 1000 ou 10000 lignes qu'il ya une valeur de drapeau potentiellement critique associé. Ce que vous avez planté est un bug de mine terrestre que, si je ne me souviens pas de vérifier dans toutes les utilisations possibles, je pourrais être confronté à un terrible problème de débogage. Toute utilisation de i devra maintenant ressembler à ceci:

if (i != 0xDEADBEEF) { // Curse the original designer to oblivion
    // Actual useful work goes here
}

Répéter l'opération pour tous les 7000 cas où vous avez besoin d'utiliser i dans votre code.

Maintenant, pourquoi est-ce qui précède pire que cela?

if (isIProperlyInitialized()) { // Which could just be a boolean
    // Actual useful work goes here
}

Au minimum, je peux repérer plusieurs questions critiques:

  1. Orthographe : Je suis un terrible dactylo. Comment facilement vous repérer dans 0xDAEDBEEF une revue de code? Ou 0xDEADBEFF? D'autre part, je sais que ma compilation sera barf immédiatement isIProperlyInitialised () (insérer obligatoire par rapport à z débat ici).
  2. Exposition de sens . Plutôt que d'essayer de cacher vos drapeaux dans le code, vous avez intentionnellement créé une méthode que le reste du code peut voir.
  3. Opportunités pour le couplage . Il est tout à fait possible qu'un pointeur ou de référence est connecté à un cache vaguement défini. Un contrôle d'initialisation pourrait être surchargée de vérifier d'abord si la valeur est dans le cache, puis d'essayer de le ramener dans le cache et, si tout cela échoue, return false.

En bref, il est tout aussi facile d'écrire le code que vous avez vraiment besoin car il est de créer une mystérieuse valeur magique. Le code-mainteneur du futur (qui très probablement vous) vous remerciera.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top