C言語関係掲示板

過去ログ

No.995 char型を%xで出力すると変になる

[戻る] [ホームページ]
No.12982

ダンプ形式でprintf
投稿者---なつ(2004/02/27 16:24:56)


こんにちは。
初歩的な質問で申し訳ありませんが、
どうにも解決できないことがあって困ってます。

charの2バイトの文字の2バイト目をダンプ形式(HEX)で
printf文で表示したいのです。
実際には
char test[3];
memset(test, NULL, sizeof(test));
memcpy(test, "12", 2);
これで0x3132とtestの中身はなってると思いますが、
2バイト目の32という値のみを表示するにはどうすればいいのでしょう?
printf("test = %02x", test[1]);
printf("test = %02x", *(short*)&test[1]);
とかいろいろ試してみたんですけど、どうにもうまくいきません・・・
どなたか宜しくお願いいたします。


No.12983

Re:ダンプ形式でprintf
投稿者---nop(2004/02/27 16:42:49)


>とかいろいろ試してみたんですけど、どうにもうまくいきません・・・

どううまくいかないのでしょうか?

No.12984

Re:ダンプ形式でprintf
投稿者---なつ(2004/02/27 16:48:24)


>どううまくいかないのでしょうか?
すみません、例の挙げ方が悪かったです。
char test[2];
memset(test, NULL, sizeof(test));
memset(&test[1], 0xf9, 1);
と入れて
printf("test = %x", test[1]);
とすると
実行結果は
test = f9 となって欲しいのに
test = fffffff9 となってしまいます。
2バイト目に0xf9などではなく0x67などを入れると
test = 67  と正しく表示されます。




No.12985

Re:ダンプ形式でprintf
投稿者---なつ(2004/02/27 16:53:29)


>printf("test = %x", test[1]);
>とすると
>実行結果は
>test = f9 となって欲しいのに
>test = fffffff9 となってしまいます。

ちなみに
printf("test = %x", *(short*)&test); と
printf("test = %x", *(short*)&test[0]); ならうまくいきます。
何故test[1]ではだめか不思議です。






No.12989

Re:ダンプ形式でprintf
投稿者---たいちう(2004/02/27 17:24:15)


char型は -128〜127 を表すので、0xf9 を代入すると負の数になります。
printfの型指定で"x"は、符号なし16進整数なので、
char型の 0xf9(10進数で-7) は、
int型の0xfffffff9(10進数で-7)に型変換されて表示されてます。

test の宣言を unsigned char に変更すると、お望みの結果になると思います。

No.12990

Re:ダンプ形式でprintf
投稿者---NykR(2004/02/27 17:24:17)


>>printf("test = %x", test[1]);
>>とすると
>>実行結果は
>>test = f9 となって欲しいのに
>>test = fffffff9 となってしまいます。
>
>ちなみに
>printf("test = %x", *(short*)&test); と
>printf("test = %x", *(short*)&test[0]); ならうまくいきます。
>何故test[1]ではだめか不思議です。

取り敢えず%dで表示してみてはどうでしょうか?

char型は、printfに渡される際にint型に変換されます。
16進数表示の f9で表される、signed char型の値は、大抵の処理系では、-7ですが
int型の-7の16進数表示は、大抵の処理系で、fffffff9 となります。

testが、unsigned char型の場合、f9で表される値は 24となり、
int型の24もまた、f9と表示されるので、そのように宣言すればよいでしょう。

それかビットマスクをかけて上位( (sizeof(int) - 1) * CHAR_BIT )ビットをゼロにするか、ですね。

#何もつけない char型が unsigned char になるか、signed char になるかは処理系に依存します。

No.12988

Re:ダンプ形式でprintf
投稿者---nop(2004/02/27 17:24:05)


>printf("test = %x", test[1]);

printf("test = %x", 0xFFU&test[1]);

に変更してみて下さい。

No.12992

Re:ダンプ形式でprintf
投稿者---なつ(2004/02/27 17:31:55)


>printf("test = %x", 0xFFU&test[1]);

みなさん、ありがとうございました。
おかげさまで解決しました。
ところで0xFFUとは何を意味するのですか?
これで期待通りの結果が出ましたが、何故こうなるのかがわかりません。
ご教授宜しくお願いいたします。


No.12993

Re:ダンプ形式でprintf
投稿者---たか(2004/02/27 17:53:23)


>みなさん、ありがとうございました。
>おかげさまで解決しました。
>ところで0xFFUとは何を意味するのですか?
>これで期待通りの結果が出ましたが、何故こうなるのかがわかりません。
>ご教授宜しくお願いいたします。

C言語の算術変換の規則により、片方被演算数がunsigned intであれば、
他方もunsigned intに変換されます。つまり(char)0xf9 がsigned か
unsigned charかに関わらず、結果はunsigned intとなり、符号無しと
なります。つまり符号拡張が行われないまま & 演算子が適用されます。

もっと簡単な方法として

 printf("test = %02x\n", *(unsigned char *)&test[1]);

と書く方法があります。これですとtest[1]の内容をunsigned charとして
読み取り、その結果をint型へと格上げしますが、この際に符号の拡張は
行われないので、同じ結果が得られます。

No.12996

Re:ダンプ形式でprintf
投稿者---たか(2004/02/27 20:32:36)


>C言語の算術変換の規則により、片方被演算数がunsigned intであれば、
>他方もunsigned intに変換されます。

申し訳ありません。その前に整数格上げがありました。ですから charは
符号有り、無しに応じてintに格上げされ、符号部も無視あるいは延長され
ますが、それと0xffuとのand演算を行えば下位8ビットのみを残して後は
マスクされますね。その結果符号部は抹消され unsigned char を int に
格上げしたのと同じ結果になります。

もしintとunsigned intの and の結果がどんな型になるのかご存じの方
教えて下さい。お願いします。

No.12997

Re:ダンプ形式でprintf
投稿者---YuO(2004/02/27 21:06:24)


>もしintとunsigned intの and の結果がどんな型になるのかご存じの方
>教えて下さい。お願いします。

unsigned intになります。
少し詳しい型変換の説明」の,「3.通常の算術型変換」に記述があります。


>>printf("test = %02x\n", *(unsigned char *)&test[1]);

これは,
printf("test = %02x\n", (unsigned char)test[1]);
でいいですね。


No.13024

Re:ダンプ形式でprintf
投稿者---たか(2004/03/01 14:39:43)


>>もしintとunsigned intの and の結果がどんな型になるのかご存じの方
>>教えて下さい。お願いします。
>
>unsigned intになります。
>「少し詳しい型変換の説明」の,「3.通常の算術型変換」に記述があります。
>
>
>>>printf("test = %02x\n", *(unsigned char *)&test[1]);
>
>これは,
>printf("test = %02x\n", (unsigned char)test[1]);
>でいいですね。

ありがとうございました。それと私の方に冗長な表現があったようです
ね。失礼致しました。

No.12994

Re:ダンプ形式でprintf
投稿者---nop(2004/02/27 17:55:44)


>>printf("test = %x", 0xFFU&test[1]);
>ところで0xFFUとは何を意味するのですか?
>これで期待通りの結果が出ましたが、何故こうなるのかがわかりません。

printf() などの可変個引数では char や short などは、
int への型変換が行われます。
# 「%x」に対応する型も int です

この時、対象のデータが負数の場合、
符号拡張が行われ、0xF9 などの値は 0xFFFFFFF9 などの値に変換されます。
# int が 16 bit の環境では 0xFFF9 などになるでしょう

なので、0xFFUとの論理積をとり不要なビットを0にしてから、
printf() に値を渡してあげればいいわけです。


No.12995

Re:ダンプ形式でprintf
投稿者---NykR(2004/02/27 19:59:57)


># 「%x」に対応する型も int です

%x に対応する型は unsigned int です。
つまり、%x で表示されるのは単なるビットパターンです。
ですから、0xf9 が 0x80000079 と表示される処理系もあり得ます。

No.13003

Re:ダンプ形式でprintf
投稿者---NykR(2004/02/28 11:10:28)


>ですから、0xf9 が 0x80000079 と表示される処理系もあり得ます。

0xf9は10進数にすると24だから、0xf9と表示されるはずですね。
そうではなくて、「-7」という式で表される値の内部表現が 0x80000079 というビットパターンになっている処理系もありえるという話でした。
0x80000079は、10進数表示で 2147483897 となる値の16進数表示であって、「-7」の16進数表示ではありません。

#しかし、これについては、「%xで表示される 0xfffffff9 は『4294967289』を意味するのであって『-7』を意味するのではない」と書いておけば済んでましたね。内部表現がどうのこうのという話は本質とは無関係でした。

No.12986

Re:ダンプ形式でprintf
投稿者---Cマニア(超初心者)(2004/02/27 17:21:20)


>charの2バイトの文字の2バイト目をダンプ形式(HEX)で
>printf文で表示したいのです。
>実際には
>char test[3];
>memset(test, NULL, sizeof(test));
>memcpy(test, "12", 2);
>これで0x3132とtestの中身はなってると思いますが、
>2バイト目の32という値のみを表示するにはどうすればいいのでしょう?
>printf("test = %02x", test[1]);
>printf("test = %02x", *(short*)&test[1]);
>とかいろいろ試してみたんですけど、どうにもうまくいきません・・・
>どなたか宜しくお願いいたします。

#include<stdio.h>
#include<memory.h>

int main(void){

    char test[3];

    memset( test, NULL, sizeof(test));
    memcpy( test, "12", 2);

    printf("test[0] = %x\n", test[0]);
    printf("test[1] = %x\n", test[1]);

    return 0;
}

これで実行結果が、
 test[0] = 31
 test[1] = 32
こうなりましたけど、こういうことではないのですか?

No.12987

Re:ダンプ形式でprintf
投稿者---なつ(2004/02/27 17:23:57)


すみません、例の挙げ方が悪かったです。
前述したのですが
char test[2];
memset(test, NULL, sizeof(test));
memset(&test[1], 0x99, 1);
と入れて
printf("test = %x", test[1]);
とすると
実行結果は
test = 99 となって欲しいのに
test = ffffff99 となってしまいます。
2バイト目に0x99などではなく0x67などを入れると
test = 67  と正しく表示されます。


No.13021

Re:ダンプ形式でprintf
投稿者---なつ(2004/03/01 10:02:40)


みなさん、今回は本当にありがとうございました。
大変勉強になりました。
また何かありましたら宜しくお願いいたします。