短い符号なし整数の配列がある場合。
array[k+1] を 8 ビット左にシフトすると、array[k+1] の下半分に 8 ビットが入りますか?
それとも、要素に割り当てられたスペースの外に出たために、単にドロップオフするのでしょうか?
彼らは降ります。このように他のビットに影響を与えることはできません。それを試してみてください:
#include <stdio.h>
void print_a (short * a)
{
int i;
for (i = 0; i < 3; i++)
printf ("%d:%X\n", i, a[i]);
}
int main ()
{
short a[3] = {1, -1, 3};
print_a (a);
a[1] <<= 8;
print_a (a);
return 0;
}
出力は
0:1 1:FFFFFFFF 2:3 0:1 1:FFFFFF00 2:3
次の配列要素に持ち越さずに、データ型を完全に削除します。
そのような動作が必要な場合は、次のようなコードを自分でコーディングする必要があります (配列全体を 4 ビット左シフトします)。
#include <stdio.h>
int main(void) {
int i;
unsigned short int a[4] = {0xdead,0x1234,0x5678,0xbeef};
// Output "before" variables.
for (i = 0; i < sizeof(a)/sizeof(*a); i++)
printf ("before %d: 0x%04x\n", i, a[i]);
printf ("\n");
// This left-shifts the array by left-shifting the current
// element and bringing in the top bit of the next element.
// It is in a loop for all but hte last element.
// Then it just left-shifts the last element (no more data
// to shift into that one).
for (i = 0; i < sizeof(a)/sizeof(*a)-1; i++)
a[i] = (a[i] << 8) | (a[i+1] >> 8);
a[i] = (a[i] << 8);
// Print the "after" variables.
for (i = 0; i < sizeof(a)/sizeof(*a); i++)
printf ("after %d: 0x%04x\n", i, a[i]);
return 0;
}
これは以下を出力します:
before 0: 0xdead
before 1: 0x1234
before 2: 0x5678
before 3: 0xbeef
after 0: 0xad12
after 1: 0x3456
after 2: 0x78be
after 3: 0xef00
これについて考える方法は、C (およびほとんどのプログラミング言語) の実装でarray[k] << 8
は、配列 [k] をレジスタにロードし、レジスタをシフトしてから、レジスタを配列 [k] に格納することです。したがって、array[k+1] は変更されません。
例として、foo.c
:
unsigned short array[5];
void main() {
array[3] <<= 8;
}
次の命令を生成します。
movzwl array+6(%rip), %eax
sall $8, %eax
movw %ax, array+6(%rip)
これにより、array[3] が %eax にロードされ、変更され、元に戻されます。
int データ型の C 定義では、含まれるビット数が指定されておらず、システムに依存することに注意してください。int は元々、プロセッサの「自然な」ワード サイズになるように意図されていましたが、常にそうであるとは限らず、int に 16、32、64、または 24 ビットのような奇数が含まれている場合もあります。
保証されている唯一のことは、unsigned int が 0 から UINT_MAX までのすべての値を保持できることです。ここで、UINT_MAX は少なくとも 65535 である必要があります。したがって、int 型には、必要な範囲の値を保持するために少なくとも 16 ビットが含まれている必要があります。
そのため、整数の配列を 8 ビットシフトすると、各 int が個別に変更されますが、このシフトは必ずしも「配列の半分」になるとは限らないことに注意してください。
unsigned int を 8 ビット左にシフトすると、下位 8 ビットがゼロで埋められます。上位 8 ビットは破棄されます。それらが配列内にあるかどうかは問題ではありません。
ちなみに、8 ビットが unsigned int の半分であるかどうかはシステムによって異なりますが、32 ビット システムでは、8 ビットは通常 unsigned int の 4 分の 1 です。
unsigned int x = 0x12345678;
// x is 0x12345678
x <<= 8;
// x is 0x34567800