Cで整数がshort
にキャストされたときに何が起こるかを誰かが明確にできますか? Raspberry Piを使用しているので、int
は32ビットであるため、short
は16ビットでなければなりません。
たとえば、次のCコードを使用するとします。
int x = 0x1248642;
short sx = (short)x;
int y = sx;
x
は切り捨てられますが、誰かが正確に説明できますか?シフトは使用されていますか?数値は32ビットから16ビットにどのくらい正確に切り捨てられますか?
ISO C標準によれば、整数を符号付き型に変換し、値がターゲット型の範囲外にある場合、結果は実装定義です。 (または、実装定義のシグナルを生成できますが、これを行うコンパイラーは知りません。)
実際には、最も一般的な動作は、上位ビットが破棄されることです。したがって、int
が32ビットでshort
が16ビットであると仮定すると、値0x1248642
を変換すると、おそらく0x8642
のようなビットパターンが生成されます。 (ほとんどすべてのシステムで使用される)符号付き型の2の補数表現を想定すると、高位ビットは符号ビットであるため、結果の数値は-31166
になります。
int y = sx;
これには、short
からint
への暗黙的な変換も含まれます。 int
の範囲は、少なくともshort
の範囲全体をカバーすることが保証されているため、値は変更されません。 (あなたの例では、sx
の値はたまたま負であるため、この表現の変更にはsign extensionが含まれる可能性が高く、1
符号ビットをすべてに伝播します。結果の上位16ビット。)
前述したように、これらの詳細は言語標準では必要ありません。値をより狭い型に切り捨てたい場合は、おそらく次のように、符号なしの型(言語指定のラップアラウンド動作があります)およびおそらく明示的なマスキング操作を使用するのが最善です。
unsigned int x = 0x1248642;
unsigned short sx = x & 0xFFFF;
16ビット変数に押し込みたい32ビットの量がある場合、最初にすべきことは、値が収まらない場合のコードの動作を決定することです。それを決めたら、あなたが望むことをするCコードを書く方法を理解することができます。切り捨てが必要な場合もあります。その場合、特に符号なしの型を使用している場合は、タスクが簡単になります。範囲外の値はエラーである場合があります。その場合、その値を確認し、エラーの処理方法を決定する必要があります。場合によっては、値を切り捨てるのではなく飽和させたい場合があります。そのためには、コードを記述する必要があります。
Cで変換がどのように機能するかを知ることは重要ですが、その質問でstartを指定すると、間違った方向から問題に近づいている可能性があります。
32ビットの値は、16 cmの長さのパンに詰め込んだ場合、32 cmの長さのバナナパンが切り取られるのと同じ方法で16ビットに切り捨てられます。それの半分は収まり、それでもバナナのパンで、残りは「なくなって」しまいます。
切り捨ては、CPUレジスタで発生します。これらのサイズは異なります:8/16/32/64ビット。今、次のようなレジスタを想像できます。
<--rax----------------------------------------------------------------> (64-bit)
<--eax----------------------------> (32-bit)
<--ax-----------> (16-bit)
<--ah--> <--al--> (8-bit high & low)
01100011 01100001 01110010 01110010 01111001 00100000 01101111 01101110
x
には、最初に32ビット値0x1248642
。メモリ*では、次のようになります。
-----------------------------
| 01 | 24 | 86 | 42 |
-----------------------------
31..24 23..16 15..8 7..0
これで、コンパイラーはx
をレジスターにロードします。それから、最下位16ビット(つまり、ax
)をロードし、sx
に格納するだけです。
*エンディアンネスは、単純化のために考慮されていません
おそらく、コードはそれ自体を語らせます:
#include <stdio.h>
#define BYTETOBINARYPATTERN "%d%d%d%d%d%d%d%d"
#define BYTETOBINARY(byte) \
((byte) & 0x80 ? 1 : 0), \
((byte) & 0x40 ? 1 : 0), \
((byte) & 0x20 ? 1 : 0), \
((byte) & 0x10 ? 1 : 0), \
((byte) & 0x08 ? 1 : 0), \
((byte) & 0x04 ? 1 : 0), \
((byte) & 0x02 ? 1 : 0), \
((byte) & 0x01 ? 1 : 0)
int main()
{
int x = 0x1248642;
short sx = (short) x;
int y = sx;
printf("%d\n", x);
printf("%hu\n", sx);
printf("%d\n", y);
printf("x: "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN"\n",
BYTETOBINARY(x>>24), BYTETOBINARY(x>>16), BYTETOBINARY(x>>8), BYTETOBINARY(x));
printf("sx: "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN"\n",
BYTETOBINARY(y>>8), BYTETOBINARY(y));
printf("y: "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN"\n",
BYTETOBINARY(y>>24), BYTETOBINARY(y>>16), BYTETOBINARY(y>>8), BYTETOBINARY(y));
return 0;
}
出力:
19170882
34370
-31166
x: 00000001 00100100 10000110 01000010
sx: 10000110 01000010
y: 11111111 11111111 10000110 01000010
ご覧のとおり、int
-> short
は期待どおり下位16ビットを生成します。
short
をint
にキャストすると、上位16ビットが設定されたshort
が生成されます。ただし、これは実装固有の未定義の動作であると思われます。あなたは本質的に16ビットのメモリを整数として解釈し、そこにあるゴミの余分な16ビットを読み取ります(コンパイラがニースでバグをより迅速に見つけたい場合は1です)。
Ithink以下を実行しても安全であるはずです:
int y = 0x0000FFFF & sx;
明らかに、失われたビットを取り戻すことはできませんが、これにより、上位ビットが適切にゼロ化されることが保証されます。
誰もが信頼できる参照でshort-> int high bit動作を検証できる場合、それは高く評価されるでしょう。
注: this answer から適応されたバイナリマクロ。
単に上位16ビットが整数から切り捨てられます。したがって、あなたのショートは0x8642
これは実際には負の数です-31166
。
sx
値は、x
の最下位2バイトと同じになります。この場合、0x8642になり(16ビット符号付き整数として解釈される場合)、10進数で-31166になります。