他の人が今述べたように、ptr[k] = ((val >> (k*len)) && 0xFF);
あなたがそれを望むかどうかはわかりません. &&
演算子はブール演算子です。(value >> (k*len))
がゼロ以外の値で、がゼロ以外の値である場合0xFF
、格納される値ptr[k]
は 1 になります。それがブール演算子の仕組みです。&
の代わりに使用するつもりだったのかもしれません&&
。
さらに、型に適したシフト演算子を使用することを選択しましたunsigned
が、符号付き型にはさまざまな移植性のない側面があります。xx = xx |(ptr[m]<<(m*8));
たとえば、符号付き整数のオーバーフローが発生する可能性があるため、未定義の動作を引き起こす可能性があります。
C では、sizeof (char)
は常に1です。これは、型を表すために使用される s の数がsizeof
演算子によって示されるためです。char
例えば。s を表すために使用される s の数をsizeof (int)
示します。変わるものです。したがって、コードはa 型に依存するべきではありません。char
int
CHAR_BIT
sizeof
int
実際、コードを移植可能にしたい場合は、たとえばに 32767 より大きい値または -32767 より小さい値を格納できると期待すべきではありません。パディング ビットが存在する可能性があるため、これはサイズに関係ありません。要約すると、sizeof
a 型は、格納できる値のセットを必ずしも反映しているわけではありません!
アプリケーションの変数のタイプを選択します。移植可能です。アプリケーションがその範囲を超える値を必要としない場合は、問題ありませんint
。それ以外の場合はlong int
、移植可能に -2147483647 と 2147483647 の間 (および含む) の値を格納できる の使用を検討することをお勧めします。それを超える値が必要な場合は、 a を使用しますlong long int
。これにより、少なくとも -9223372036854775807 から 9223372036854775807 までの値で構成される保証範囲が得られます。それを超える値は、おそらくGMPなどの多精度演算ライブラリに値します。
負の値を使用する予定がない場合は、unsigned
型を使用する必要があります。
移植可能な整数型の選択を考慮すると、これらの整数をファイルに書き込み、ファイルからそれらの整数を読み取る移植可能な方法を考案できることが理にかなっています。符号と絶対値を次のように抽出しますunsigned int
。
unsigned int sign = val < 0; /* conventionally 1 for negative, 0 for positive */
unsigned int abs_val = val;
if (val < 0) { abs_val = -abs_val; }
...そして、 と の 8 ビット チャンクの配列を作成し、abs_val
一緒sign
にマージします。int
-32767 から 32767 までの値しか格納できないため、16 ビットしか格納できないというポータブルな意思決定を使用することを既に決定しています。その結果、ループやビットごとのシフトは必要ありません。乗算を使用して符号ビットを移動し、除算/モジュロを使用して絶対値を減らすことができます。符号は従来、配列の先頭 (ビッグ エンディアン) または末尾 (リトル エンディアン) にある最上位ビットに付いていると考えてください。
unsigned char big_endian[] = { sign * 0x80 + abs_val / 0x100,
abs_value % 0x100 };
unsigned char lil_endian[] = { abs_value % 0x100,
sign * 0x80 + abs_val / 0x100 };
このプロセスを逆にするために、反対の演算を互いに逆に実行します (つまり、乗算の代わりに除算とモジュロを使用し、除算と加算の代わりに乗算を使用し、符号ビットを抽出して値を再形成します)。
unsigned int big_endian_sign = array[0] / 0x80;
int big_endian_val = big_endian_sign
? -((array[0] % 0x80) * 0x100 + array[1])
: ((array[0] % 0x80) * 0x100 + array[1]);
unsigned int lil_endian_sign = array[1] / 0x80;
int lil_endian_val = lil_endian_sign
? -((array[1] % 0x80) * 0x100 + array[0])
: ((array[1] % 0x80) * 0x100 + array[0]);
のコードはもう少し複雑にlong
なり、2 項演算子を使用する価値があります。符号と絶対値の抽出は基本的に同じままで、変更点は変数の型だけです。移植可能に表現可能な値のみを気にするという決定を下したため、ループはまだ必要ありません。long val
aから an に変換する方法は次のunsigned char[4]
とおりです。
unsigned long sign = val < 0; /* conventionally 1 for negative, 0 for positive */
unsigned long abs_val = val;
if (val < 0) { abs_val = -abs_val; }
unsigned char big_endian[] = { (sign << 7) | ((abs_val >> 24) & 0xFF),
(abs_val >> 16) & 0xFF,
(abs_val >> 8) & 0xFF,
abs_val & 0xFF };
unsigned char lil_endian[] = { abs_val & 0xFF,
(abs_val >> 8) & 0xFF,
(abs_val >> 16) & 0xFF,
(sign << 7) | ((abs_val >> 24) & 0xFF) };
...そして、署名された値に戻す方法は次のとおりです。
unsigned int big_endian_sign = array[0] >> 7;
long big_endian_val = big_endian_sign
? -((array[0] & 0x7F) << 24) + (array[1] << 16) + (array[2] << 8) + array[3]
: ((array[0] & 0x7F) << 24) + (array[1] << 16) + (array[2] << 8) + array[3];
unsigned int lil_endian_sign = array[3] >> 7;
long lil_endian_val = lil_endian_sign
? -((array[3] & 0x7F) << 24) + (array[2] << 16) + (array[1] << 8) + array[0]
: ((array[3] & 0x7F) << 24) + (array[2] << 16) + (array[1] << 8) + array[0];
unsigned
とタイプのスキームを考案するのはあなたに任せますlong long
...そしてコメントのためにフロアを開きます: