2

n3337.pdfドラフト5.3.1.8には、次のように記載されています。

単項演算子のオペランドは、-算術型またはスコープなしの列挙型でなければならず、結果はそのオペランドの否定になります。汎整数拡張は、積分オペランドまたは列挙オペランドで実行されます。符号なし数量の負の数は、2ⁿからその値を減算することによって計算されます。ここで、nはプロモートされたオペランドのビット数です。結果のタイプは、プロモートされたオペランドのタイプです。

場合によってはそれで十分です。unsigned intが32ビット幅(-(0x80000000u)) == 0x80000000uだとしたら、そうではありませんか?

それでも、符号なし0x80000000の単項マイナスについては何も見つかりません。また、C99標準ドラフトn1336.pdf、6.5.3.3はそれについて何も言っていないようです:

単項演算子の結果は、その(プロモートされた)オペランドの負数です。整数拡張はオペランドで実行され、結果はプロモートされたタイプになります。

UPDATE2:unsignedintが32ビット幅であると仮定しましょう。したがって、問題は、C(符号付きおよび符号なし)の単項マイナス、およびC ++(符号付きのみ)の単項マイナスについてはどうでしょうか。

UPDATE1:実行時の動作とコンパイル時の動作(つまり、定数畳み込み)の両方が興味深いものです。

(関連:abs(0x80000000)== 0x80000000なのはなぜですか?

4

2 に答える 2

5

あなたの質問のために、あなたが含めた引用の重要な部分はこれです:

符号なし数量の負の数は、2ⁿからその値を減算することによって計算されます。ここで、nはプロモートされたオペランドのビット数です。

したがって、の値を知るには、のタイプのビット数-0x80000000uを知る必要があります。これは少なくとも32ですが、私たちが知っているのはこれだけです(実装内の型のサイズに関する詳細情報はありません)。のいくつかの値が与えられると、結果がどうなるかを計算できます。n0x80000000un

n   | -0x80000000u 
----+--------------
32  | 0x80000000
33  | 0x180000000
34  | 0x380000000
48  | 0xFFFF80000000
64  | 0xFFFFFFFF80000000

(たとえば、unsigned intが16ビットでunsigned longが64ビットの実装では、が64になりますn)。


C99には、§6.2.5タイプp9に隠された同等の表現があります。

結果の符号なし整数型で表現できない結果は、結果の型で表現できる最大値より1大きい数を法として減少するため、符号なしオペランドを含む計算はオーバーフローすることはありません。

-ゼロ以外の符号なしオペランドに対する単項演算子の結果は、常にこのルールによってキャッチされます。

32ビットの場合、接尾辞がないかどうかに関係なく、intのタイプは0x80000000になります。したがって、結果はタイプがの値のままになります。unsigned intu0x80000000unsigned int

代わりに10進定数を使用する場合2147483648、それはタイプlongを持ち、計算は署名されます。結果は-2147483648、タイプがの値になりますlong

于 2012-02-28T00:52:57.973 に答える
2

n1336、6.3.1.3の符号付き整数と符号なし整数では、段落2で符号なし整数への変換が定義されています。

それ以外の場合、新しいタイプが符号なしの場合、値が新しいタイプの範囲内になるまで、新しいタイプで表すことができる最大値より1つ多い値を繰り返し加算または減算することにより、値が変換されます。

したがって、32ビットのunsigned intの場合、-0x80000000u==-0x80000000 + 0x100000000==0x80000000u

于 2012-02-28T00:51:52.717 に答える