#pragma twice

KAB-studio > プログラミング > #pragma twice > 205 Version 11.05 signed char と unsigned char

#pragma twice 205 Version 11.05 signed char と unsigned char

前のページへ 表紙・目次へ 次のページへ

 Version 11.05
signed char と unsigned char

今回は signed と unsigned について説明します
それ自体は前にやったよね。符号があるのとないのって
 Version 4.06 ( No.056 ) で説明したように、 signed が符号あり、 
unsigned が符号なしです
でもさ、それってあんま関係ないと思うんだけど。だって文字でしょ?
それがおおありなんです。まず、その singed とかを説明したページにあ
るコードをもう一度試してみます

void Compare()
{
    char ch = -1;
    unsigned char uch = ch;

    if( ch < uch )
    {
        TRACE( "%d < %u\n", ch, uch );
    }
}
// -1 < 255

何も付けてないと signed と同じだから、 ch の方は signed です。で、
それと unsigned を比較すると
そうそう、同じ -1 でも、 unsigned だと 255 になっちゃうんだよね
あ、でも勘違いしないで欲しいんだけど、ビット的には ch も uch も同
じ 0xFF だからね
え、そうなの?

    unsigned char uch = ch;

ってした時には、実際には何も起きてません。こっちじゃなくて

    if( ch < uch )

このとき、 ch は 0xFF を -1 、 uch は 0xFF を 255 ってみなして
それで比較しちゃうわけね
言い換えると、これは < の機能ってことかも
機能??
そう。 < は signed か unsigned か調べて、それを元に整数値に変換し
て比較してるってこと
そういう機能が備わってる……?
この辺はちょっと難しいかもね。演算子ってただ計算をするだけじゃなく
て、いろんな機能もあるんです。そういうののひとつってところかな
うーん……
まぁそれは今は置いておいて、重要なのは signed か unsigned かで比較
したときの結果が変わっちゃうってこと
それって重要なの?
すごく重要。だって前回、 Shift JIS のリードバイトの範囲とトレイル
バイトの範囲って言ったでしょ
あーっ!!! そっか、その範囲に入ってるかどうかって、もちろん比較
しなきゃいけないわけだから……
では実際に試してみます。リードバイトかどうか判別する関数の signed 
を使うほうから

bool IsReadByte_bad( signed char p_ch )
{
    if(
        ( ( 0x81 <= p_ch ) && ( p_ch <= 0x9F ) ) ||
        ( ( 0xE0 <= p_ch ) && ( p_ch <= 0xFC ) )
        )
    {
        // リードバイトです。
        return true;
    }

    return false;
}

これを次のような関数から呼びます

void Use_IsReadByte_bad()
{
    const signed char pchStr[] = "あ";
    bool bResult = IsReadByte_bad( pchStr[0] );
    if( bResult == true )
    {
        TRACE( "リードバイトです。" );
    }
    else
    {
        TRACE( "トレイルバイトです。" );
    }
    // トレイルバイトです。
}

 "あ" のリードバイトを渡してるんだから、絶対にリードバイトになるは
ずなんだけど
げ、実行したらトレイルバイトって言われた
 "あ" の文字コードは 0x82 0xA0 
範囲には入ってるよねぇ
でも

    0x81 <= p_pch

この p_pch には 0x82 が入ってるわけだから、普通に比較すると

    0x81 <= 0x82

だからあってるはずよね
ところが、 p_pch は signed だから符号あり。そうなると、互いに符号
ありの比較になります。その場合

    -127 <= -126

となるため、当てはまらなくなってしまうんです
……質問!
はい火美ちゃん
 0x81 が -127 とかってどうやればわかる?
それはこうしてください

    TRACE( "%d\n", 0xFFFFFF81 );
    // -127

う、なんか F が多い
こうすると -127 が出てきます
なんで F 入れなきゃいけないの?
う”……それはかなーり難しいから今度
う”ー……あ、もひとつ質問
はい火美ちゃん
 signed で比較すると逆になっちゃったけど、それって16進数だと大き
いのに10進数だと小さいってことだよね。なんか変くない?
さっきのページで教えたでしょ。 -1 は 11111111 、つまり 0xFF 
あ、そっか、逆になるんだ
だから、実際にはこんな感じ

16進数 : 0x00 - 0x7F - 0x80 - 0xFF
signed   :    0    127   -128     -1
unsigned :    0    127    128    255

 signed だと、 0x7F と 0xF8 で逆になるって考えてください
むー、ややこしい……
まぁそういうわけで、この 0x7F 以上の数を使う文字の場合、 signed で
計算するとうまくいきません。なので、 unsigned を使います

bool IsReadByte( unsigned char p_ch )
{
    if(
        ( ( 0x81u <= p_ch ) && ( p_ch <= 0x9Fu ) ) ||
        ( ( 0xE0u <= p_ch ) && ( p_ch <= 0xFCu ) )
        )
    {
        // リードバイトです。
        return true;
    }

    return false;
}

// 使います。
void Use_IsReadByte()
{
    const unsigned char pchStr[] = "あ";
    bool bResult = IsReadByte( pchStr[0] );
    if( bResult == true )
    {
        TRACE( "リードバイトです。" );
    }
    else
    {
        TRACE( "トレイルバイトです。" );
    }
    // リードバイトです。
}

うん、こっちならちゃんとリードバイトって出た
あと、今回は省略するけど、どっちの文字の方が大きいか、っていうのを
比較するときにも関係するから
文字の大きさ?
たとえば

ABC
BBC

ってあった場合、辞書に並べるときはこの順番でしょ
そういう大きい小さい?
そう。こういう時 A < B みたいな比較をするわけだけど
これも unsigned じゃないとうまくいかないわけね
さて、ここまでを踏まえて、これからすごくややこしい話をします
う”っ、な、なに?
今見たように、 char は unsigned char とした方が安全です
 unsigned にすると出るデメリットはないの?
ありません
ならそうした方がいいわけ……よね
なんだけど、そうしません
そこがややこしいとこなんだ。なんで?
うーん、一番の理由は慣例的にそう、だからかな。 unsigned を付けない 
char しか使わない、っていうのが普通だし、問題になるのは文字の比較と
か四則演算するときくらいだから、その時キャストすればいいし
……二番目の理由は?
実は、 char が signed とは決まってないんです
へ?
 char が実際には signed か unsigned かは開発環境によって違うんで
す。 Visual C++ は char は signed 。 unsigned なのもあるし、最新の
VC .Net は好きな方を選べるしね
ならやっぱり、常に unsigned にするべきなんじゃない?
確かにそうなんだけどね……これがきっと最大の理由なんだけど、 
unsigned char から char へはキャストが必要なんだけど、ランタイムとか 
API とかは
げ。そっか、普通の char だから、渡すたびにキャストしなきゃいけない
んだ……
それはあまりにも大変だし、そうなると結局
何も付けない char 使うしかないってわけね……

/*
    Preview Next Story!
*/
なんだか、政治的策略を感じるわ……
そういう部分もあるかも
否定しないのー!?
こういうことは派閥争いと無縁じゃないから
そんでもって掲示板で罵り合うことになるんだ……ぶるぶる
というわけで次回
< Version 11.06 Unicode >
につづく!
今度もまたそういうのだ……
また!?
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。