12

フォームの式を含む作業中のコードを扱っています

-(sizeof(struct foo))

つまり、 a の否定でありsize_t、C および C++ 標準がこれを確認したときにコンパイラに何を要求するかについては不明です。具体的には、ここや他の場所を見回すとsizeof、 型の符号なし整数値が返されますsize_t。符号なし整数を否定するときの指定された動作の明確な参照が見つかりません。あるとすれば、それは何ですか?

編集: わかりましたので、符号なし型の算術演算に関していくつかの良い答えがありますが、これが実際にそのようなものであるかどうかは明らかではありません。これが否定されるとき、それは符号なし整数で動作していますか、それとも符号付き型に変換してそれで何かをしていますか? 標準から期待される動作は、「それが同様の大きさの負の数であると想像し、符号なし値に「オーバーフロー」ルールを適用する」ことですか?

4

6 に答える 6

21

ISO C および ISO C++ 標準の両方が、符号なし算術演算が 2 nを法とすることを保証します。つまり、オーバーフローまたはアンダーフローについては、「ラップアラウンド」します。ISO C++ の場合、これは 3.9.1[basic.fundamental]/4 です。

宣言された符号なし整数は、 2 nunsignedを法とする算術法則に従うものとします。ここで、nは、整数の特定のサイズの値表現のビット数です。41

...

41) これは、結果の符号なし整数型で表現できない結果が、結果の符号なし整数型で表現できる最大値よりも 1 大きい数値を法として減らされるため、符号なし算術演算がオーバーフローしないことを意味します。

ISO C(99) の場合、6.2.5/9 です。

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

つまり、結果は と同じであることが保証されますSIZE_MAX - (sizeof(struct foo)) + 1


ISO 14882:2003 5.3.1.7:

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

于 2009-08-12T22:19:19.240 に答える
2

http://msdn.microsoft.com/en-us/library/wxxx8d2t%28VS.80%29.aspx

符号なし量の単項否定は、オペランドの値を 2 nから減算することによって実行されます。ここで、n は、指定された符号なし型のオブジェクトのビット数です。(Microsoft C++ は、2 の補数演算を使用するプロセッサで実行されます。他のプロセッサでは、否定のアルゴリズムが異なる場合があります。)

つまり、正確な動作はアーキテクチャ固有になります。もし私があなたなら、そのような奇妙な構造を使用することは避けます。

于 2009-08-12T22:14:46.567 に答える
2

符号なし数値の否定は、ワード全体に lsb を伝播して、後続のビット演算のマスクを形成するのに役立ちます。

于 2009-12-04T16:23:12.203 に答える
1

現在のC++ドラフト標準のセクション5.3.1の文8から:

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

したがって、結果の式はまだ符号なしであり、説明されているように計算されます。

ユーザー@outisはコメントでこれについて言及しましたが、outisはそうではなかったので、私はそれを答えに入れるつもりです。outisが戻ってきて答えたら、代わりにそれを受け入れます。

于 2009-08-12T22:47:27.980 に答える
1

考えられるのは頭が痛いほど間違っていることだけです...

size_t size_of_stuff = sizeof(stuff);

if(I want to subtract the size)
    size_of_stuff = -sizeof(stuff);

size_t total_size = size_of_stuff + other_sizes;

オーバーフローが特徴!

于 2009-08-12T22:30:04.100 に答える
1

size_t実装定義の符号なし整数型です。

size_t値を否定すると、通常の unsigned modulo 動作の type の結果が得られる可能性があります。size_tたとえば、size_tが 32 ビットでsizeof(struct foo) == 4、次に-sizeof(struct foo) == 4294967292、または 2 32 -4 であると仮定します。

1 つ例外があります。単項-演算子は、整数昇格(C) または整数昇格(C++) (これらは本質的に同じものです) をそのオペランドに適用します。size_tが少なくとも と同じ幅の場合int、このプロモーションは何もせず、結果のタイプは になりsize_tます。しかし、intが より広い場合size_tINT_MAX >= SIZE_MAXのオペランドはから に-「昇格」さsize_tintます。そのありそうもないケースでは、-sizeof(struct foo) == -4.

その値をsize_tオブジェクトに代入すると、元の に変換されsize_t、期待どおりの値が得られSIZE_MAX-4ます。しかし、そのような変換がなければ、驚くべき結果が得られることがあります。

size_tが よりも狭い実装について聞いたintことがないので、これに遭遇する可能性は低いです。しかし、潜在的な問題を説明するunsigned short、仮想の狭い型の代用として使用するテスト ケースを次に示します。size_t

#include <iostream>
int main() {
    typedef unsigned short tiny_size_t;
    struct foo { char data[4]; };
    tiny_size_t sizeof_foo = sizeof (foo);
    std::cout << "sizeof (foo) = " << sizeof (foo) << "\n";
    std::cout << "-sizeof (foo) = " << -sizeof (foo) << "\n";
    std::cout << "sizeof_foo = " << sizeof_foo << "\n";
    std::cout << "-sizeof_foo = " << -sizeof_foo << "\n";
}

私のシステム( 16-bit short、 32-bit int、および 64-bitsize_tがある)の出力は次のとおりです。

sizeof (foo) = 4
-sizeof (foo) = 18446744073709551612
sizeof_foo = 4
-sizeof_foo = -4
于 2015-11-10T01:12:40.517 に答える