2

gccビットごとの左シフト ( <<) の奇妙な動作。これが私のコードです:

#include <stdio.h>
#include <string.h>

void foo(int n){
  printf("1<<32:%d\n", 1<<32);
  printf("1<<(32-n):%d\n", 1<<(32-n));
}

int main(){
    foo(0);
}

パラメータとして 0 を渡すと、結果が異なる可能性があります。ソースコードのコンパイル:

$gcc main.c -o demo -lm -pthread -lgmp -lreadline 2>&1
main.c: In function 'foo':
main.c:5:3: warning: left shift count >= width of type [enabled by default]

プログラムの実行:

$demo

1<<32:0
1<<(32-n):1

この結果は、コンパイル オンライン サイトから得たものです。

0 を渡した場合、foo 関数の出力を 0 にするにはどうすればよいですか? (現在は代わりに 1 を出力します)

4

6 に答える 6

0

C 標準ISO 9899:1999の第 6.5.7 章によるとBitwise shift operators:

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

コンパイラが 2 つの式を異なる方法で処理するのは奇妙です。しかし、これはとにかく未定義の動作を引き起こすため、問題にはなりません。必要なことは、評価の前にオペランドをチェックして、それが有効な式であることを確認することです。

于 2013-06-02T03:18:12.667 に答える
0

gcc警告の問題が何であるかを示しています:

main.c:5:3: warning: left shift count >= width of type [enabled by default]

シフトは型のサイズよりも小さくする必要があります。そうしないと、未定義の動作になります。C99 ドラフト標準セクションの6.5.7 ビット単位のシフト演算子の段落3には、次のように記載されています。

[...]右オペランドの値が負であるか、昇格した左オペランドの幅以上である場合、動作は未定義です。

なぜ最初printfのものと2番目のものは違うのですか? を使用してビルドする-fdump-tree-originalと、 に対して生成された次のコードが表示されfooます。

printf ((const char * restrict) "1<<32:%d\n", 0);
printf ((const char * restrict) "1<<(32-n):%d\n", 1 << 32 - n);

未定義の動作0と一致するように最適化されている最初のケースのようです。コンパイラは、動作しているように見える動作を含め、何でもできます。

于 2013-06-02T02:43:18.627 に答える
0

驚かないでください。32 ビットの int を扱っているので、1<<32 を実行すると、そのセット ビットが int のすぐ後ろにシフトされ、全体がゼロになります。

たとえば、バイナリで:

    33222222 22211111 11111000 00000000
    10987654 32109876 54321098 76543210
 1: 00000000 00000000 00000000 00000001

   ^--- position #32
于 2013-06-02T02:43:40.807 に答える
-1

私は最終的に回避策を見つけ、少なくとも出力を同一にします。

#include <stdio.h>
#include <string.h>

void foo(int n){
  printf("1<<32:%d\n", 1<<32);
  printf("1<<(32-n):%d\n", (1<<(31-n))<<1);
}

int main(){
    foo(0);
}
于 2013-06-02T16:33:05.493 に答える