10

~0が最大ワードサイズのビット 1 を評価することは知っていますが (したがって、移植性に注意が必要です)、なぜ((1 << N) - 1)が推奨されないのかまだわかりませんか?

2 番目のフォームを使用して問題が発生した場合は、共有してください。

4

6 に答える 6

10

次の行を見てください。

1. printf("%X", ~(~0 << 31) );
2. printf("%X", (1 << 31) - 1 );

1はコンパイルされ、期待どおりに動作します。

行は、式で整数オーバーフローを2警告します。

これは、がデフォルトで符号付きint1 << 31として扱われるためです。したがって、可能な最小の整数です。1 << 31 = -2147483648

その結果、休む1とオーバーフローが発生します。

于 2011-10-05T10:07:21.073 に答える
4

最初の形式は絶対に好まれません。決して使用すべきではないとまで言います。負のゼロをサポートしない 1 の補数システムでは、トラップ表現~0である可能性が非常に高いため、使用すると UB が呼び出されます。

一方、オーバーフローするため、32 ビットと1<<31仮定すると UB も UB になります。int

定数として 31 を本当に意味する場合0x7fffffffは、マスクを記述する最も簡単で正しい方法です。の符号ビット以外のすべてが必要な場合はintINT_MAXマスクを記述する最も簡単で最も正しい方法です。

ビットシフトがオーバーフローしないことがわかっている限り、最下位ビットが設定され(1<<n)-1たマスクを作成する正しい方法です。符号の問題やシフトでのオーバーフローを心配する必要がないように、キャストまたは暗黙の変換nを使用することをお勧めします。(1ULL<<n)-1

~ただし、何をするにしても、符号付き整数で演算子を使用しないでください。これまで。

于 2011-10-05T18:59:26.030 に答える
1

符号付きの値に対するシフト操作または補数操作は、単に悪い考えです。ビット パターンは常に符号なしの型で生成し、(必要であれば) 符号付きの対応する部分に転置する必要があります。通常、ビットパターンでは、処理するビット数を制御する必要があるため、プリミティブ型を使用することもアイデアとしてはあまり良くありません。

だから私はいつも次のようなことをします

-UINT32_C(1)
~UINT32_C(0)

これらは完全に同等であり、最終的にはこれを使用するだけになりUINT32_MAX、Co.

シフトは、次のような完全にシフトしない場合にのみ必要です

(UINT32_C(1) << N) - UINT32_C(1)
于 2011-10-05T11:18:18.090 に答える
0

私はどちらかを優先しません(1<<N)が、値が 64 ビットでなければならないのに "1" が 32 ビット (int は 32 ビット) であり、結果が N>=31 の場合に間違っているという多くのバグを見てきました。 . 1 ではなく 1ULL を指定すると修正されます。それは、そのようなシフトの1つの危険です。

また、CHAR_BIT*sizeof(int) 以上の位置による int のシフト (同様に、CHAR_BIT*sizeof(long long) 以上の位置による long long (多くの場合 64 ビット) の場合) は定義されていません。そのため、次のように右にシフトする方が安全かもしれません:~0u>>(CHAR_BIT*sizeof(int)-N)ですが、この場合 N は 0 にはなりません。

于 2011-10-05T10:14:05.427 に答える
0

編集:愚かなエラーを修正しました。可能性のあるオーバーフローの問題を指摘しました。

ある形式が他の形式よりも好まれるとは聞いたことがありません。どちらの形式もコンパイル時に評価されます。私は常に 2 番目の形式を使用していますが、問題が発生したことはありません。両方の形式は、読者にとって完全に明確です。

他の回答では、2 番目の形式でのオーバーフローの可能性が指摘されました。

それらの中から選択することはほとんどありません。

于 2011-10-05T10:14:07.367 に答える
-2

推奨されない理由
~0 は単一サイクル操作であるため、より高速です ((1<最初にシフトを実行し、次に算術演算である減算を実行します。したがって、減算により、多くのサイクルが消費され、したがって不要なオーバーヘッドが発生します。

さらに
、 ((1 << N)-1) または ((M << N)-1) を実行する場合は、すべてのビットをフラッシュするため、N が M のビット単位のサイズを参照すると仮定すると同じです。ここで 1 は整数で、現在のほぼすべてのプラットフォーム 32/64 ビットでは通常 32 ビットなので、N は 32 と見なすことができます。

ただし、1 を long に型キャストして (((long)1 << 32) -1) を実行すると、結果は同じにはなりません。ここでは、32 の代わりに 64 を使用する必要があります。64 は long のビット単位のサイズです。

于 2011-10-05T10:20:48.883 に答える