Cでの16進文字の印刷


103

1行の文字を読み取ってから、その文字に相当する16進数を出力しようとしています。

たとえば"0xc0 0xc0 abc123"、最初の2文字がc016進数で残りの文字がabc123ASCIIであるという文字列がある場合、次のようになります。

c0 c0 61 62 63 31 32 33

ただし、printf使用%xすると

ffffffc0 ffffffc0 61 62 63 31 32 33

なしで必要な出力を取得するにはどうすればよい"ffffff"ですか?そして、c0(および80)だけがを持ちffffff、他の文字はないのはなぜですか?


バイトの配列と一致する文字列は次のようになります..."\xc0\xc0abc123"
burito

回答:


132

はシステムに署名されているffffffため、charが表示されています。Cでは、のような可変引数関数は、printfより小さいすべての整数推進するintにはintcharは整数(この場合は8ビットの符号付き整数)なので、charはint符号拡張を介して昇格されます。

以来、c0及び80(8ビット整数として負の)先頭の1ビットを持っているあなたのサンプル中の他のものはないが、それらは符号拡張されています。

char    int
c0 -> ffffffc0
80 -> ffffff80
61 -> 00000061

これが解決策です:

char ch = 0xC0;
printf("%x", ch & 0xff);

これにより、上位ビットがマスクされ、必要な下位8ビットのみが保持されます。


15
cast toを使用した私のソリューションunsigned charは、x86-64のgcc4.6では1つの命令が小さい...
lvella

1
多分私は助けることができます。指定子xは符号なしの型を必要とするため、これは(技術的に)未定義の動作ですが、chはintに昇格されます。正しいコードは、単にchをunsignedにキャストするか、またはキャストをunsigned charと指定子に使用しますhhx
2501

1
私が持っている場合printf("%x", 0)、何も印刷されません。
グスタボメイラ

最小値が0に設定されているため、何も印刷されません。これを修正するには、printf("%.2x", 0);描画される最小文字数を2に増やしてみてください。最大値を設定するには、を付加します。番号付き。たとえば、強制的に描画できるのは2文字だけですprintf("%2.2x", 0);
user2262111

@brutal_lobsterの回答のようにprintf("%x", ch & 0xff)単に使用するよりも優れている理由は何ですか?printf("%02hhX", a)
maxschlepzig

62

実際、intへの型変換があります。また、%hhx指定子を使用して、タイプを強制的にcharにすることもできます。

printf("%hhX", a);

ほとんどの場合、最小の長さも設定して、2番目の文字をゼロで埋める必要があります。

printf("%02hhX", a);

ISO / IEC 9899:201xは言う:

7長さ修飾子とその意味は次のとおりです。hh次のd、i、o、u、x、またはX変換指定子が、signed charまたはunsigned char引数に適用されることを指定します(引数は整数の昇格に従って昇格されます。ただし、その値は、出力前に、signed charまたはunsigned charに変換されます。またはその次


30

符号なし文字を作成できます。

unsigned char c = 0xc5;

それを印刷すると、与えC5られませんffffffc5

127より大きい文字のみffffffが負である(charが署名されている)ため、が出力されます。

またはchar、印刷中にwhile をキャストできます。

char c = 0xc5; 
printf("%x", (unsigned char)c);

3
真のベストアンサー、可能な限りデータ宣言に近い(ただし、近くない)明示的な型指定を+1します。
Bob Stein

13

おそらく値0xc0をchar変数に格納しています。これはおそらく符号付きの型であり、値は負(最上位ビットセット)です。次に、印刷時にそれがに変換されint、意味上の同等性を維持するために、コンパイラーは余分なバイトに0xffを埋め込むので、負数intは負数と同じ数値になりますchar。これを修正するにはunsigned char、印刷時ににキャストします。

printf("%x", (unsigned char)variable);

13

を使用hhprintfて、引数がunsigned charであることを通知できます。使用0ゼロパディングを取得し、22に幅を設定するxか、X下/大文字進文字に。

uint8_t a = 0x0a;
printf("%02hhX", a); // Prints "0A"
printf("0x%02hhx", a); // Prints "0x0a"

編集:読者が2501の主張が「正しい」形式指定子ではないという懸念がある場合は、もう一度printfリンクを読むことをお勧めします。具体的には:

%cはint引数を期待しますが、可変個関数が呼び出されたときに整数の昇格が行われるため、charを渡しても安全です。

固定幅文字タイプ(int8_tなど)の正しい変換仕様は、ヘッダー<cinttypes>(C ++)または<inttypes.h>(C)で定義されています(ただし、PRIdMAX、PRIuMAXなどは%jd、%juなどと同義です

符号付きと符号なしの彼のポイントについては、値は常に正であり、signed intに簡単にフィットする必要があるため、この場合は問題ではありません。とにかく、符号付き16進数形式指定子はありません。

編集2:(「いつ許可するか」が間違っている場合):

311ページ(PDFの329)で実際のC11標準を読むと次のことがわかります。

HH:次のことを指定しdioux、またはX変換指定が適用されるsigned charか、unsigned char引数(引数が整数プロモーションに従って進められているであろうが、その値に変換しなければならないsigned charか、unsigned char印刷する前に)。または、次のn変換指定子がsigned char引数へのポインターに適用されること。


タイプuint8_tの指定子が正しくありません。固定幅タイプは特別な印刷指定子を使用します。参照:inttypes.h
2501

そうですが、すべての可変引数整数は暗黙的にintに昇格されます。
Timmmm 2016

そうかもしれませんが、Cが定義されている限り、正しい指定子を使用しない場合の動作は未定義です。
2501

ただし、%x 正しい指定子です。(charそして)[ en.cppreference.com/w/cpp/language/variadic_arguments]にunsigned char昇格します。あなたは、あなたのプラットフォームに適合しないもののためにPRI指定子を使用する必要があります例えば- 。intintunsigned int
Timmmm、2016年

%xintではなくunsigned intの場合は正しいです。char型とunsigned char型はintに昇格されます。さらに、uint8_tがunsigned charとして定義されている保証はありません。
2501

2

おそらく、signed char配列から印刷しています。unsigned char配列から出力するか、値を0xffでマスクします(例:ar [i]&0xFF)。高(符号)ビットが設定されているため、c0値は符号拡張されています。


-1

このようなものを試してください:

int main()
{
    printf("%x %x %x %x %x %x %x %x\n",
        0xC0, 0xC0, 0x61, 0x62, 0x63, 0x31, 0x32, 0x33);
}

これはこれを生成します:

$ ./foo 
c0 c0 61 62 63 31 32 33
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.