-1

このコードはそれ自体が物語っていますが、ここで何か言わないと質問を投稿できません!

#include <stdio.h>
#include <limits.h>

void rightshift_test(int const shift_amount) {
  unsigned long a = 0xabcd1234abcd1234UL;
  printf("a: %lx, shift_amount:%d\n", a, shift_amount);
  unsigned long const b = a >> shift_amount;
  printf("b: %lx\n", b);
}

int main() {
  rightshift_test(56);
  rightshift_test(60);
  rightshift_test(61);
  rightshift_test(62);
  rightshift_test(63);
  rightshift_test(64);
  return 0;
}

それでも、質問を投稿できません。ここでコードが実行されています:

gcc -Wall -Wextra -Werror foo.c -o foo
./foo
a: abcd1234abcd1234, shift_amount:56
b: ab
a: abcd1234abcd1234, shift_amount:60
b: a
a: abcd1234abcd1234, shift_amount:61
b: 5
a: abcd1234abcd1234, shift_amount:62
b: 2
a: abcd1234abcd1234, shift_amount:63
b: 1
a: abcd1234abcd1234, shift_amount:64
b: abcd1234abcd1234

そして、それがあまり明白でない場合のために、ここに私のコンパイラと私のマシンの詳細があります.

$ gcc --version
i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (dot 3)

$ echo $MACHTYPE
x86_64-apple-darwin10.0
4

1 に答える 1

3

ISO C99 標準には、ビットシフト演算子を扱う次の小さなスニペットがあります。

shift-expression:
       additive-expression
       shift-expression << additive-expression
       shift-expression >> additive-expression

整数昇格は各オペランドで実行されます。結果の型は、昇格された左オペランドの型です。右オペランドの値が負の値であるか、プロモートされた左オペランドの幅以上である場合、動作は未定義です。

unsigned longつまり、64 ビット (実装内)を 64 ビット以上シフトしようとすると、すべての賭けがオフになります。0、元の値、または 42 を返すことができます。ハード ドライブをフォーマットし、ポルノを上司にメールで送信することもできます (実装で実際にこれを行うのを見たことがありません)。

一部の実装 (または実装の基盤となるハードウェア) では、関連するビットのみを効果的に使用してこれらの命令を最適化することがあります。言い換えれば、64 ビット値の場合、0 から 63 のオペランドを与えるために、最下位 7 ビットのみを使用して (事実上andでそれを -ing ) 使用することができます。0x3f

その場合、64 & 0x3fは 0 に等しいので、事実上ノーオペレーションです。

いずれにせよ、なぜそのように振る舞うかは推測です。未定義の動作は、本当に避けるべきものです。動作を期待どおりに動作させたい場合は、次のように変更します

unsigned long const b = a >> shift_amount;

次のようなものに:

unsigned long const b = (shift_amount < 64) ? a >> shift_amount : 0;

このコードに見られるように (私のシステムでは 64 ビット値は ULL です):

#include <stdio.h>
#include <limits.h>

void rightshift_test(int const shift_amount) {
    unsigned long long a = 0xabcd1234abcd1234ULL;
    printf("a: %llx, shift_amount:%d: ", a, shift_amount);
    unsigned long long const b = (shift_amount < 64) ? a >> shift_amount : 0;
    printf("b: %llx\n", b);
}

int main() {
    rightshift_test(56);
    rightshift_test(60);
    rightshift_test(61);
    rightshift_test(62);
    rightshift_test(63);
    rightshift_test(64);
    rightshift_test(99);
    return 0;
}

これの出力は次のとおりです。

a: abcd1234abcd1234, shift_amount:56: b: ab
a: abcd1234abcd1234, shift_amount:60: b: a
a: abcd1234abcd1234, shift_amount:61: b: 5
a: abcd1234abcd1234, shift_amount:62: b: 2
a: abcd1234abcd1234, shift_amount:63: b: 1
a: abcd1234abcd1234, shift_amount:64: b: 0
a: abcd1234abcd1234, shift_amount:99: b: 0
于 2012-09-13T08:14:55.167 に答える