1

私はこのコードを持っています:

unsigned char *command = "0000";
unsigned char foo = (hex_char_to_int(command[0]) << 4) | hex_char_to_int(command[1]);
unsigned char bar = (hex_char_to_int(command[2]) << 4) | hex_char_to_int(command[3]);
printf("foo: %02x, bar: %02x\r\n", foo, bar);

次の関数を使用します。

unsigned char hex_char_to_int(unsigned char ch) {
    switch (ch){
        case '0': return 0;
        case '1': return 1;
        case '2': return 2;
        case '3': return 3;
        case '4': return 4;
        case '5': return 5;
        case '6': return 6;
        case '7': return 7;
        case '8': return 8;
        case '9': return 9;
        case 'A': return 0xA;
        case 'B': return 0xB;
        case 'C': return 0xC;
        case 'D': return 0xD;
        case 'E': return 0xE;
        case 'F': return 0xF;
        case 'a': return 0xA;
        case 'b': return 0xB;
        case 'c': return 0xC;
        case 'd': return 0xD;
        case 'e': return 0xE;
        case 'f': return 0xF;
        default: return 0;
    }
}

結果は次のとおりです。

"JW\xd6\x96'$$LK\x90\xbbar: 3030\r\r\n"

これは、AT89C55WD 上の Keil C51 コンパイラでprintf()、シリアル ポート経由で実行されます。

何が起こっている?

編集

printf行を次のように変更します

printf("%02x%02x\r\n", (unsigned int)foo, (unsigned int)bar);

のバグのようprintfです。プログラマーの皆さん、嘘をつくデバッグツールを絶対に作らないでください。お願いです。

4

1 に答える 1

4

私が知る限り、そのコードは適合する C コンパイラで動作するはずです。

私は Keil C51 を使用したことはありませんが、C 標準の要件に完全に従っていないことを示すいくつかの兆候を見てきました。

(この回答には、以前はいくつかの可能な提案が含まれていましたが、そのほとんどはうまくいきませんでした。興味がある場合は、編集履歴を参照してください。)

c 標準で要求されているように、unsigned char渡された引数がorに昇格されprintfていないようです。intunsigned int

コードの移植性を適度に保ちながらこれを回避するには、キャストを追加して と の値を に明示的に変換foobarますunsigned int

printf("foo: %02x, bar: %02x\r\n", (unsigned int)foo, (unsigned int)bar);

(はテキスト ストリームのシステムの行末シーケンスに自動的に変換さ\rれるため、通常は必要ありませんが、おそらく Keil C51 は異なる動作をします。)\n

繰り返しますが、どちらの方法でも機能するはずですが、この変更は Keil 51のバグ機能を回避する可能性があります。

アップデート :

Keil C51 のオンライン ドキュメントを確認しました。printfのドキュメントには、タイプを指定するのと同じように、 タイプを指定するbおよびタイプを含む、いくつかの非標準機能が示されています。Bcharllong

b;に(または、または) 引数をB渡すことができないため、標準 C では必要ありません。そのような引数は、または場合によっては に昇格されます。これと、あなたが遭遇したエラーから、Keil C51 はナロー引数を可変個引数関数に昇格させず、特に引数はにも にも昇格させないと推測します。charunsigned charsigned charprintfintunsigned intunsigned charintunsigned int

それは理由を説明します

printf("%02x", foo);

機能しなかった理由とその理由

printf("%02x", (unsigned int)foo);

やりました。

このコンパイラは、小型の 8 ビット マイクロプロセッサを対象としています。シングルバイト引数を暗黙的に拡大したくないのは理にかなっています。著者は適合性よりもパフォーマンスを選択したようです。これは完全に有効な決定です。(ドキュメントがこれについてより明示的であるとよいでしょう。または、何かを見逃している可能性があります。)

おそらく、unsigned char値を 16 進数で出力するための推奨される方法は次のとおりです。

printf("foo: %02bx, bar: %02bx\r\n", foo, bar);

これは Keil C51 に固有のものであり、コードを他のプラットフォームに移植できないことに注意してください。しかし、繰り返しになりますが、このような小さなシステムで実行するために作成されたコードは、とにかく移植可能ではありません。

unsigned int前に提案したように、へのキャストも機能するはず"%02bx"ですが、引数を 1 バイトとして渡すことができるため、 を使用する方が時間とコード サイズの点で効率的です。

于 2013-08-14T20:42:27.793 に答える