9ー10日目 - naskをLinuxで使えるようにする 2016/03/22, 27

naskをLinuxで使えるようにする

続きです。たぶんまだまだ時間かかります。

unsigned char と (signed) char 間の変換

unsigned char と (signed) char 間の変換

osaskはなにぶん古いソフトウェアのため、以下のようなコードがかなりある

typedef unsigned char UCHAR;

int main(int argc, UCHAR **argv)
{
...
}
		  

このコードは当然通らない、main関数の引数はchar**と決まっている(unsignedではない)

typedef unsigned char UCHAR; のような独自型定義も、D言語ならば不要なのだがC++なのでしかたない。

河合氏は、unsignだとビットが目一杯使えるぐらいに考えていたのだろうか。

C/C++ char型の符号有無

C/C++ char型の符号有無という良記事があったので引用しておく

プログラミング言語C/C++のchar型が、符号あり/符号なしのいずれかは処理系定義(implementation defined)。各コンパイラでの実装についてメモ。

まとめ:

・char型を「符号あり」(signed char)と仮定しないこと。(とはいえ、この仮定をおくコードは多い…)
・特にARMアーキテクチャ(近年ではAndroid NDK)では既定で char型=「符号なし」 となることに注意。

osaskは間違いなく

char == signed char
で使っている

C++のキャストを使う

では具体的にどのように変換を行うべきか、以下を参照されたい

Converting from signed char to unsigned char and back again?

signed char x = -100;
unsigned char y;

y = (unsigned char)x;                    // C言語的 static
y = *(unsigned char*)(&x);               // C言語的 reinterpret
y = static_cast<unsigned char>(x);       // C++な static
y = reinterpret_cast<unsigned char&>(x); // C++な reinterpret
		  

int から char* への代入

int から char* への代入

osaskはなにぶん古いソフトウェアのため、以下のようなコードがかなりある

...
	UCHAR buf[2 * 8], *bp; /* bufは適当にmallocした方がいいかも */
...
	bp = putimm(i, &bp[1]); // (1) putimmはint型を返す
		  

このコードは通らない、詳しい説明は Cast from char * to int loses precision を参照。 要は32bit専用のコードになっており、64bit環境ではコンパイルできない

共用体を定義して使い回す作戦

対策については右のリンクを参照 Converting an int into a 4 byte char array (C) サンプルコードを以下に

// 共用体の宣言
typedef union {
    UINT integer;
    UCHAR byte[4];
} nask32bitInt;

// 宣言(基本はunsigned charのポインタとして使用)
nask32bitInt* bp; // 元コード: UCHAR* bp;

// 添字アクセス
bp->byte[0] = 0x00; // 元コード: bp[0] = 0x00;

// ユーティリティ関数 (ucharに入ってるデータをnask32bitIntにコピーして返す)
static nask32bitInt* ucharToNask32bitIntPtr(UCHAR* uchar) {
    nask32bitInt* t;
    std::memcpy(t->byte, uchar, sizeof t->byte);
    return t;
};
         

その他の修正

その他の修正

・C++11以降を使うのでnew/deleteはできるだけ使用せず、スマートポインタを使っていく

・C++11以降を使うのでマクロから変更可能であればconstexprを使う

・C++11以降を使うので従来の配列から変更可能であればstd::arrayを使う

// UCHARの配列宣言時
std::unique_ptr<UCHAR> labelbuf(new UCHAR[nask_LABELBUFSIZ]);
// constexpr
constexpr UINT REM_ADDR      = 0xe0;
// std::array
std::array<int, 3> gparam;
		  

そんなこんなでとりあえずビルドは通るようになってきた。今日のところはここまで。