なんとな~くしあわせ?の日記

「そしてそれゆえ、知識そのものが力である」 (Nam et ipsa scientia potestas est.) 〜 フランシス・ベーコン

BYTEとWORDの変換(C/C++)

C/C++言語は動作するプラットフォームによって姿を変える。さながらカメレオンのように動作するプラットフォームの色に染まるのだ。クロスプラットフォームで動作するネイティブプログラムで特に苦労するのは、微妙にいろいろ型が異なることだ。
例えは以下のサイトにあるような大量のtypedef...typedef...

ここの表をちょっと写させてもらう
データ型 - Win32 API 階梯

C の型 Win32 API での別名
char CHAR
unsigned char BYTE
short SHORT
unsigned short WORD
int INT
unsigned int UINT
long LONG
unsigned long DWORD / ULONG
float FLOAT
double DOUBLE
void VOID
void * HANDLE

例えばBYTEならば、ソースコードに以下のように書くとLinuxでも同じことが出来る。

typedef unsigned char BYTE;

そして素のC/C++にはBYTEという型はない。BYTEは幻術だったのだ…
だからJavaのbyteクラスとWindowsのtypedefのBYTEは全く別物だ。

プラットフォームごとのサイズの違い

型のバイト数はプラットフォームによって異なる。調査したものだけここに載せる(あくまで参考レベル)

C の型 Win32 API での別名 Linux x86_64 Mac OS X x86_64 Win32
char CHAR 1BYTE 1BYTE 1BYTE
unsigned char BYTE 1BYTE 1BYTE 1BYTE
short SHORT 2BYTE 2BYTE 2BYTE
unsigned short WORD 2BYTE 2BYTE 2BYTE
int INT 4BYTE 4BYTE 4BYTE
unsigned int UINT 4BYTE 4BYTE 4BYTE
long LONG 8BYTE 8BYTE 4BYTE
unsigned long DWORD / ULONG 8BYTE 8BYTE 4BYTE
float FLOAT 4BYTE 4BYTE 4BYTE
double DOUBLE 8BYTE 8BYTE 8BYTE
void VOID - - -
void * HANDLE - - -

C++特有のキャスト方法

説明は詳しい人にしてもらうのがいい

C++のキャスト方法が詳しく書かれている
C++編(言語解説) 第24章 C++独自のキャスト

C言語のキャストとC++のキャストの比較
本の虫: 邪悪なC形式のキャストにしかできないこと

型変換で必要なのは2つstatic_castreinterpret_castだ。

・static_castは単純な型から型への変換(ex: long -> int)
・reinterpret_castはポインタを使う変換だ(ex: wxString(reinterpret_cast(m_ptr)))

こっちは使い方が難しい。まあポインタ使うやつがreinterpret_castで、使わないほうがstatic_castみたいなノリで。

BYTEをWORDにキャスト

ありえないキャスト?ノンノン、知らないだけ

wandboxっていうオンラインコンパイラがあるらしいんすよぉ…
[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ

#include <iostream>

#ifdef _WIN32
   #include <Windows.h>
#else
   typedef unsigned short WORD;
   typedef unsigned char  BYTE;
#endif

int main()
{
    // サイズはナンボ?
    std::cout << sizeof(BYTE) << std::endl;
    std::cout << sizeof(WORD) << std::endl;

    // なんか文字列が入ってるやつを変換
    BYTE aquei[] = {0xe9, 0x98, 0xbf, 0xef, 0xbc, 0xb1, 0xe6, 0xad, 0xa3, 0xe4, 0xbc, 0x9d , 0x00 };
    // Windows使ってる方は最初からバイナリをShift_JISで定義するといいよ
    // BYTE aquei[] = {0x88,0xa2,0x82,0x70,0x90,0xb3,0x93,0x60, 0x00};

    // const char* 型に変換できる。やったぜ。
    // &をつけると先頭のポインタを渡せる
    const char* str = reinterpret_cast<const char*>(&aquei);
    puts(str);

    // 10進数で19800を16進にすると下記の通り
    // BYTE number[] = {0x4D, 0x58}; // <= リトルエンディアンなので左は間違い
    BYTE number[] = {0x58, 0x4D};     // <= 逆からブチ込んでいくスタイル
    WORD* w = reinterpret_cast<WORD*>(&number);
    std::cout << *w << std::endl;

    return 0;
}

出力

Start

1
2
阿Q正伝
19800

0

Finish

動作検証環境
Debian GNU/Linux (7.3), GCC-4.6ぐらい
Windows 7 64bit, Visual Studio 2012 Express Edition

型変換についてはまだまだ追記するつもりです