記事検索

検索ワードを入力してください。
Sky Tech Blog
大きな​型に​代入すると​符号が​意図通りに​ならない

大きな​型に​代入すると​符号が​意図通りに​ならない

型キャストと符号の扱いについて説明しています。特に、符号なし型から符号あり型へのキャスト時に発生する問題と、その解決方法について具体的なコード例とアセンブラの動作を交えて解説しています。

早速ですが、下記のような実装があった場合、代入された変数の値はどうなるでしょうか?

WORD wHoge = -1;
DWORD dwHoge = wHoge;
DWORD dwCastHoge = (DWORD)wHoge;
int nHoge = wHoge;
int nCastHoge = (int)wHoge;

結論から申し上げますと、これらの代入後の変数の「値は全て65535」となり、-1ではなくなり(=符号が無くなる状態)ます。

WORD型はunsigned short型ですので、同じく符号なしのunsigned int型のDWORD型に入れたら符号が無しの65535となるのは理解できます。
しかしながら、符号ありのint型にキャストをしても符号が無くなる…というのは腑に落ちない結果です。

【補足】
int型で-1の値は0xFFFFFFFFですが、00FFFFとなってしまい、65535となりました。

ちなみに、今回のケースで正しいキャストは何だったかというと、

WORD wHoge = -1;
int nHoge = (short)wHoge;

一旦2バイトで符号ありのShort型にキャストすることで-1(=0xFFFFFFFF)の値となります。

この時のコンパイル後のアセンブラを下記に比較してみます。

・int nHoge = (int)wHoge;
007DE049 movzx eax,word ptr [wHoge]
007DE04D mov dword ptr [dwHoge],eax

・int nHoge = (short)wHoge;
007DE065 movsx eax,word ptr [wHoge]
007DE069 mov dword ptr [dwShortCastHoge],eax

movzx:代入の余剰領域を0で埋める
movsx:代入の余剰領域を元の値が負ならFで、正なら0で埋める

こんな感じで小さな型を大きな型に入れるときに生成されるアセンブラのニーモニックが異なってきます。

  • intキャストでダメだったのは、元の型がunsignedなのでmovzxが選択されたためです。
    開発環境によってはうまく行くケースもあるかと思いますが、今回のようにNGとなるケースも実際にあります。
    ですので、クロスコンパイル向けの実装では特に注意しなければいけません。

POINT型の座標値X,YをMAKEDWORDして後で分解した際に、符号が吹き飛んで変な動作をしていたというのが実際の状況だったのですが、大きな型への代入では符号の保持というのも気をつけて対処する必要があります。


\シェアをお願いします!/
  • X
  • Facebook
  • LINE
キャリア採用募集中!

入社後にスキルアップを目指す若手の方も、ご自身の経験を幅広いフィールドで生かしたいベテランの方も、お一人おひとりの経験に応じたキャリア採用を行っています。

Sky株式会社のソフトウェア開発や製品、採用に関するお問い合わせについては、下記のリンクをご確認ください。
お問い合わせ
ホーム