マジック デバッグ値 (0xDEADBEEF など) をリテラルとして使用することには、具体的にどのような危険があるのでしょうか?

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

質問

言うまでもなく、ハードコーディングされた 16 進数リテラル ポインターを使用すると大惨事になります。

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

しかし、16 進数リテラルを変数として使用する場合の危険性は何ですか? 価値観?

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

これらの値が実際に「危険」である場合、 さまざまなデバッグシナリオで使用する, ということは、これらのリテラルを使用しなくても、実行時にこれらの値のいずれかに遭遇したプログラムはクラッシュする可能性があることを意味します。

16 進リテラルを使用する本当の危険性を説明したい人はいますか?


編集: 明確にしておきたいのですが、私はソース コードでの定数の一般的な使用について言及しているのではありません。具体的に話しているのは、 デバッグシナリオの問題 具体的な例として、16 進値の使用が考えられます。 0xDEADBEEF.

役に立ちましたか?

解決

私は、以前の今日質問をフォーマットするIPアドレスで提起された懸念は、一般的に進リテラルの使用が、0xdeadbeefが特定の使用に関連していなかったと信じています。少なくとも、それは私がそれを読む方法です。

私の意見では、それは小さなものですが、特に0xdeadbeefがを使用したとの懸念があります。問題は、多くのデバッガとランタイムシステムが既に割り当てられていないヒープ、スタック上の不良ポインタなどを示すマーカー値として、この特定の値を共同選択しているということです。

私は、デバッグおよびランタイムシステムは、この特定の値を使用してちょうど私の頭の上をオフに覚えていませんが、私はそれが長年にわたってこのように数回使用さ見てきました。あなたはこれらのいずれかの環境でデバッグしている場合は、あなたのコード内0xdeadbeefが定数の存在はとても良くて、あなたがRAMダンプとして有用ではありません、未割り当てのRAMまたは任意の値と区別できないだろう、と最悪の場合、あなたは警告を取得しますデバッガから。

いずれにせよ、それは私が、彼はそれがために悪かったことを言ったとき、元のコメンターが意味考えるものだ「様々なデバッグシナリオで使用する。」

他のヒント

リテラルの他の種類よりもリテラル進を使用してもより多くの危険はありません。

あなたのデバッグセッションは、あなたがそれを意図せずに、コードなどのデータを実行して終了した場合は、とにかく痛みの世界にいます。

もちろん、そこに「定数よく名前の」コードのにおい/清潔号対通常の「マジック値は」ですが、それは本当に私はあなたが話していると思う危険の一種ではありません。

いくつかの例外を除き、何も "定数" ではありません。

私たちは、「遅い変数」それらを呼び出すことを好む - 。その値が変化するので、ゆっくりと私たちはそれらを変更するために再コンパイルする気にしないこと

しかし、私たちは各インスタンスは異なる意味を持っているアプリケーションやテストスクリプトを介して、0x07のすべての多くのインスタンスを持っている必要はありません。

私たちは、それが何を意味するのか、それは完全に明確なする各定数にラベルを置きたいと思う。

if( x == 7 )

「7」は、上記の文では何を意味するのでしょうか?それは同じことです。

d = y / 7;

「7」と同じ意味ということですか?

テストケースはわずかに異なる問題です。私たちは、数値リテラルの各インスタンスの広範な、慎重な管理を必要としません。代わりに、私たちは、ドキュメントを必要とします。

私たちはすることができます - ある程度 - 「7」は、コード内のヒントのほんの少しを含むことにより、どこから来るのかを説明します。

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

"定数" を明記しなければならない - と命名 - 。正確に一度

ユニットテストの「結果」は定数と同じものではありません、それがどこから来たのか説明する際に少し注意が必要です。

リテラルHexが1のようなリテラル小数点値の任意の特別な意義は、特定のプログラムのコンテキストに起因するよりも違いはありません。

あなたは変数に0xdeadbeefを割り当てない理由はありません。

しかし、災いは小数点3735928559、またはオクタル33653337357、またはすべての最悪割り当てようとプログラマbetide:バイナリ11011110101011011011111011101111

をビッグエンディアンかリトルエンディアン?

定数は、異なるサイズのメンバーとの配列または構造体に割り当てられている場合、

一つ危険性があります。 (CLR対JVMを含む)コンパイラやマシンののエンディアンの-nessは、バイトの順序に影響します。

この問題は、もちろん、あまりにも、非定数値の真のです。

ここでは、確かに不自然な例です。 の最後の行の後に[0] をバッファの値は何ですか?

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

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

私は値としてそれを使用して任意の問題は表示されません。そのわずか数結局ます。

右の文脈で(あなたの最初の例のように)ポインタのためにハードコードされた進値を使用しても危険はありません。非常に低レベルのハードウェア開発を行う場合、特に、これはあなたが、メモリ・マップド・レジスタにアクセスする方法です。 (ただし、それは。例えば、の#defineでそれらに名前を与えることをお勧めします)しかし、アプリケーションレベルであなたが今までそのような割り当てを行う必要はありません。

私はCAFEBABEを使用します 私はそれが前に任意のデバッガによって使用される見たことがありません。

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

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

私が見た危険性はどちらの場合でも同じです。直接のコンテキストを持たないフラグ値を作成しました。何もない i どちらの場合でも、100、1000、または 10000 行で、関連する潜在的にクリティカルなフラグ値があることがわかります。あなたが埋め込んだものは地雷バグであり、私があらゆる使用法でそれをチェックすることを忘れなければ、デバッグでひどい問題に直面する可能性があります。あらゆる使用法 i 次のようになります。

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

使用する必要がある 7000 個のインスタンスすべてに対して上記の手順を繰り返します。 i あなたのコードに。

さて、なぜ上記はこれよりも悪いのでしょうか?

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

少なくとも、いくつかの重大な問題を見つけることができます。

  1. つづり:私はひどいタイピストです。コードレビューで 0xDAEDBEEF をどれくらい簡単に見つけられるでしょうか?それとも0xDEADBEFF?一方、私のコンパイルは isIProperlyInitialized() ですぐに barf することがわかっています (必須の sz ここで議論します)。
  2. 意味の露出. 。コード内でフラグを隠そうとするのではなく、コードの残りの部分から見えるメソッドを意図的に作成しました。
  3. カップリングの機会. 。ポインターまたは参照が、大まかに定義されたキャッシュに接続されている可能性は十分にあります。初期化チェックをオーバーロードして、最初に値がキャッシュ内にあるかどうかをチェックし、次にそれをキャッシュに戻そうとし、すべてが失敗した場合は false を返すことができます。

つまり、本当に必要なコードを書くのは、神秘的な魔法の値を作成するのと同じくらい簡単です。将来のコード管理者 (おそらくあなたになるでしょう) はあなたに感謝するでしょう。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top