Frage

Es ist selbstverständlich, dass hartcodiert verwenden, hex wörtliche Zeiger ist eine Katastrophe:

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

Doch was genau ist die Gefahr hex Literale als Variable Werte in mit

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

Wenn diese Werte in der Tat „gefährlich“ sind aufgrund ihres Verwendung in verschiedenen Debugging Szenarien , dann bedeutet dies, dass, selbst wenn ich ein Programm nicht über diese Literale verwenden, die möglicherweise zum Absturz auf einen dieser Werte stolpern während der Laufzeit geschieht.

Jede Sorgfalt der wirklichen Gefahren der Verwendung von Hex-Literale zu erklären?


Edit: nur zu klären, ich bin nicht auf die allgemeine Verwendung von Konstanten im Quellcode verweisen. Ich bin speziell reden über Debug-Szenario Probleme , die sich auf die Verwendung von Hex-Werte könnte kommen, mit dem spezifischen Beispiel von 0xDEADBEEF.

War es hilfreich?

Lösung

Ich glaube, die Sorge in der IP-Adresse aufgeworfene Frage Formatierung früher heute nicht auf die Verwendung von Hex-Literale im Allgemeinen verwendet war, aber die spezifische Verwendung von 0xDEADBEEF. Immerhin, das ist die Art, wie ich es lesen.

Es ist ein Anliegen, mit der Verwendung von 0xDEADBEEF insbesondere, aber meiner Meinung nach es ein kleines ist. Das Problem ist, dass viele Debugger und Runtime-Systeme haben bereits diesen besonderen Wert als Marker Wert-co entschieden nicht zugeordneten Haufen, schlechte Zeiger auf dem Stapel, um anzuzeigen, etc.

Ich erinnere mich nicht ab, die Spitze von meinem Kopf nur die Fehlersuche und Laufzeitsysteme diesen besonderen Wert zu verwenden, aber ich habe es mehrmals verwendete diese Weise über die Jahre gesehen. Wenn Sie in einer dieser Umgebungen debuggen, wird die Existenz der 0xDEADBEEF Konstante im Code von den Werten in nicht zugeordneten RAM oder was auch immer nicht zu unterscheiden sein, so bestenfalls werden Sie nicht so geeignet sind, weisen RAM-Dumps, und im schlimmsten Fall werden Sie Warnungen erhalten vom Debugger.

Wie auch immer, das ist, was ich glaube, der Original-Kommentator meinte, als er Ihnen gesagt, es ist schlecht für „Einsatz in verschiedenen Debug-Szenarien.“

Andere Tipps

Es gibt keine Gefahr mehr ein Hex-wörtlichen als jede andere Art von wörtlichen in Verwendung.

Wenn Sie Ihre Debug-Sitzung endet Daten als Code ausgeführt wird, ohne dass Sie es wollen, sind Sie in einer Welt der Schmerzen sowieso.

Natürlich gibt es den normalen „magic Wert“ vs „gut benannte Konstante“ Code Geruch / Sauberkeit Problem, aber das ist nicht wirklich die Art von Gefahr, ich glaube, Sie reden.

Mit wenigen Ausnahmen nichts ist "Konstante".

Wir bevorzugen sie „langsam Variablen“ nennen -. Deren Wert ändert sich so langsam, dass wir neu zu kompilieren nichts dagegen, sie zu ändern

Allerdings wollen wir nicht viele Fälle von 0x07 alle durch eine Anwendung oder ein Testskript haben, wobei jede Instanz eine andere Bedeutung hat.

Wir wollen auf jeden konstant ein Etikett setzen, die es völlig eindeutig macht, was es bedeutet.

if( x == 7 )

Was bedeutet „7“ in der obigen Aussage bedeuten? Ist es das gleiche wie

d = y / 7;

Ist das die gleiche Bedeutung von „7“?

Testfälle sind ein etwas anderes Problem. Wir brauchen keine umfassende, sorgfältige Verwaltung der einzelnen Instanz eines Zahlenliteral. Stattdessen müssen wir Dokumentation.

Wir können - in einem Ausmaß - erklären, wo „7“ kommt durch ein winziges bisschen einen Hinweis im Code einschließlich

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

A "Konstante" sollte festgestellt werden - und benannt -. Genau einmal

Ein „Ergebnis“ in einem Unit-Test ist nicht das Gleiche wie eine Konstante, und erfordert eine wenig Sorgfalt bei der Erklärung, woher es kam.

Ein Hex wörtliche ist nicht anders als Dezimalzahl wörtlichen wie 1. Jede besondere Bedeutung eines Wertes auf den Kontext eines bestimmten Programms zurückzuführen ist.

Es gibt keinen Grund, warum Sie 0xdeadbeef einer Variablen nicht zuweisen sollte.

Aber wehte den Programmierer, der dezimal 3735928559 zuweisen versucht, oder Oktal 33653337357, oder das Schlimmste:. Binäre 11011110101011011011111011101111

Big Endian oder Little Endian?

Eine Gefahr ist, wenn Konstanten in ein Array oder eine Struktur mit unterschiedlich großen Elementen zugeordnet ist; die Endian -ness des Compilers oder Maschine (einschließlich JVM vs CLR) wird die Reihenfolge des Bytes beeinflussen.

Dieses Problem gilt für nicht-konstante Werte, natürlich auch.

Hier ist ein zugegebenermaßen gekünstelt, Beispiel. Was ist der Wert von buffer [0] nach der letzten Zeile?

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

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

Ich sehe ein Problem nicht mit ihm als Wert verwendet wird. Es ist nur eine Zahl, nachdem alle.

Es besteht keine Gefahr einen hartcodierte Hex-Wert für einen Zeiger (wie Ihr erstes Beispiel) in dem richtigen Kontext zu verwenden. Insbesondere dann, wenn die Hardware-Entwicklung zu tun sehr niedrigem Niveau, das ist die Art und Weise Sie Memory-Mapped-Register zugreifen. (Obwohl es am besten, ihnen Namen mit einem #define zu geben, zum Beispiel.) Aber auf der Anwendungsebene sollten Sie nicht immer benötigen einen Auftrag wie das zu tun.

Ich benutze CAFEBABE Ich habe es nicht mit irgendwelchen Debugger verwendet gesehen vor.

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

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

Die Gefahr, dass ich sehe, ist die in beiden Fällen gleich: Sie haben einen Flag-Wert erstellt, die keinen unmittelbaren Kontext hat. Es gibt nichts über i in jedem Fall, die mich 100 wissen lassen, 1000 oder 10000 Zeilen, dass es ein potenziell kritischer Flagwert mit ihm verbunden ist. Was Sie schon gepflanzt ist ein Mine Fehler, der, wenn ich es in jeder möglichen Verwendung überprüfen erinnere mich nicht mehr, ich mit einem schrecklichen Debug-Problem konfrontiert werden könnte. Jede Verwendung von i wird nun wie folgt aussehen müssen:

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

Wiederholen Sie die oben für alle der 7000 Fälle, in denen Sie i in Ihrem Code verwenden müssen.

Nun, warum ist die oben schlimmer als das?

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

Als Minimum kann ich einige kritische Fragen vor Ort:

  1. Rechtschreibung : Ich bin eine schreckliche Stenotypistin. Wie leicht werden Sie 0xDAEDBEEF in einem Code-Review vor Ort? Oder 0xDEADBEFF? Auf der anderen Seite weiß ich, dass meine Kompilierung sofort auf isIProperlyInitialised barf wird () (legen Sie die obligatorische s vs. z Debatte hier).
  2. Die Exposition von Bedeutung . Anstatt zu versuchen, Ihre Fahnen in dem Code zu verstecken, haben Sie erstellt absichtlich eine Methode, die der Rest des Codes sehen.
  3. Chancen für die Kopplung . Es ist durchaus möglich, dass ein Zeiger oder eine Referenz auf eine lose definierte Cache verbunden ist. Eine Initialisierungsprüfung überlastet werden könnte, zunächst zu prüfen, ob der Wert im Cache vorhanden ist, dann versuchen Sie es in dem Cache zurück zu bringen und, wenn alles, was ausfällt, return false.

Kurz gesagt, es ist genauso einfach, den Code zu schreiben, was Sie wirklich brauchen, wie es ist, einen geheimnisvollen Magie Wert zu schaffen. Der Code-Maintainer der Zukunft (die sehr wahrscheinlich werden Sie) wird es Ihnen danken.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top