size_t 的否定(即 `-sizeof(struct foo)`))会发生什么?

发布于 2024-07-30 19:40:33 字数 402 浏览 14 评论 0原文

我正在处理一些工作中的代码,其中包含以下形式的表达式

-(sizeof(struct foo))

,即 size_t 的否定,并且我不清楚 C 和 C++ 标准在看到这种情况时对编译器的要求。 具体来说,通过查看此处和其他地方,sizeof 返回一个 size_t 类型的无符号整数值。 当否定无符号整数时,我找不到任何明确的指定行为参考。 有吗?如果有,那是什么?

编辑:好的,关于无符号类型的算术有一些很好的答案,但尚不清楚实际上是否如此。 当这个否定时,它是对无符号整数进行操作,还是转换为有符号类型并用它做一些事情? 标准的预期行为是“想象它是类似大小的负数,然后对无符号值应用‘溢出’规则”吗?

I'm dealing with some code at work that includes an expression of the form

-(sizeof(struct foo))

i.e. the negation of a size_t, and I'm unclear on what the C and C++ standards require of compilers when they see this. Specifically, from looking around here and elsewhere, sizeof returns an unsigned integral value of type size_t. I can't find any clear reference for specified behavior when negating an unsigned integer. Is there any, and if so, what is it?

Edit: Ok, so there are some good answers regarding arithmetic on unsigned types, but it's not clear that this is in fact such. When this negates, is it operating on an unsigned integer, or converting to a signed type and doing something with that? Is the behavior to expect from the standards "imagine it's the negative number of similar magnitude and then apply the 'overflow' rules for unsigned values"?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

一袭水袖舞倾城 2024-08-06 19:40:34

来自当前 C++ 草案标准 ,第 5.3.1 节第 8 句:

一元-运算符的操作数应为算术或枚举类型,结果为其操作数的否定。 整数提升是对整数或枚举操作数执行的。 无符号数量的负数是通过从 2n 中减去其值来计算的,其中 n 是提升的操作数中的位数。 结果的类型是提升的操作数的类型。

因此,结果表达式仍然是无符号的,并且按照描述进行计算。

用户 @outis 在评论中提到了这一点,但我将把它放在答案中,因为 outis 没有。 如果 outis 回来并回答,我会接受。

From the current C++ draft standard, section 5.3.1 sentence 8:

The operand of the unary - operator shall have arithmetic or enumeration type and the result is the negation of its operand. Integral promotion is performed on integral or enumeration operands. The negative of an unsigned quantity is computed by subtracting its value from 2n, where n is the number of bits in the promoted operand. The type of the result is the type of the promoted operand.

So the resulting expression is still unsigned and calculated as described.

User @outis mentioned this in a comment, but I'm going to put it in an answer since outis didn't. If outis comes back and answers, I'll accept that instead.

半世蒼涼 2024-08-06 19:40:34

size_t 是实现定义的无符号整数类型。

size_t 值求反可能会得到一个 size_t 类型的结果,并具有通常的无符号模行为。 例如,假设 size_t 为 32 位且 sizeof(struct foo) == 4,则 -sizeof(struct foo) == 4294967292 ,或 232-4。

除了一件事:一元 - 运算符应用整数提升 (C) 或整数提升 (C++)(它们本质上是相同的) thing) 到它的操作数。 如果 size_t 至少与 int 一样宽,则此提升不会执行任何操作,并且结果的类型为 size_t。 但如果 intsize_t 宽,使得 INT_MAX >= SIZE_MAX,则 - 的操作数为从 size_t“升级”为 int。 在这种不太可能的情况下,-sizeof(struct foo) == -4

如果您将该值分配回 size_t 对象,那么它将被转换回 size_t,从而生成您指定的 SIZE_MAX-4 值d 期望。 但如果没有这样的转换,您可能会得到一些令人惊讶的结果。

现在我从未听说过 size_tint 窄的实现,因此您不太可能遇到这种情况。 但这里有一个测试用例,使用 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 位 int 和 64 位 size_t)是:

sizeof (foo) = 4
-sizeof (foo) = 18446744073709551612
sizeof_foo = 4
-sizeof_foo = -4

size_t is an implementation-defined unsigned integer type.

Negating a size_t value probably gives you a result of type size_t with the usual unsigned modulo behavior. For example, assuming that size_t is 32 bits and sizeof(struct foo) == 4, then -sizeof(struct foo) == 4294967292, or 232-4.

Except for one thing: The unary - operator applies the integer promotions (C) or integral promotions (C++) (they're essentially the same thing) to its operand. If size_t is at least as wide as int, then this promotion does nothing, and the result is of type size_t. But if int is wider than size_t, so that INT_MAX >= SIZE_MAX, then the operand of - is "promoted" from size_t to int. In that unlikely case, -sizeof(struct foo) == -4.

If you assign that value back to a size_t object, then it will be converted back to size_t, yielding the SIZE_MAX-4 value that you'd expect. But without such a conversion, you can get some surprising results.

Now I've never heard of an implementation where size_t is narrower than int, so you're not likely to run into this. But here's a test case, using unsigned short as a stand-in for the hypothetical narrow size_t type, that illustrates the potential problem:

#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";
}

The output on my system (which has 16-bit short, 32-bit int, and 64-bit size_t) is:

sizeof (foo) = 4
-sizeof (foo) = 18446744073709551612
sizeof_foo = 4
-sizeof_foo = -4
动次打次papapa 2024-08-06 19:40:33

ISO C 和 ISO C++ 标准都保证无符号算术以 2n 为模 - 即,对于任何上溢或下溢,它都会“回绕”。 对于 ISO C++,这是 3.9.1[basic.fundamental]/4:

声明为unsigned的无符号整数应遵守模2n算术定律,其中n是值表示中的位数该特定大小的整数。41

...

41) 这意味着无符号算术不会溢出,因为结果无法由结果无符号整数表示
类型以比结果无符号整数可以表示的最大值大 1 的数为模进行缩减
类型。

对于 ISO C(99),它是 6.2.5/9:

涉及无符号操作数的计算永远不会溢出,因为无法由结果无符号整数类型表示的结果会以比结果类型可以表示的最大值大一的数为模进行缩减。

这意味着结果保证与 SIZE_MAX - (sizeof(struct foo)) + 1 相同。


在 ISO 14882:2003 5.3.1.7 中:

[...] 无符号数的负数
数量是通过减去来计算的
它的值来自 2n,其中
n 是位数
提升的操作数。 的类型
结果是提升的类型
操作数。

Both ISO C and ISO C++ standards guarantee that unsigned arithmetic is modulo 2n - i.e., for any overflow or underflow, it "wraps around". For ISO C++, this is 3.9.1[basic.fundamental]/4:

Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo 2n where n is the number of bits in the value representation of that particular size of integer.41

...

41) This implies that unsigned arithmetic does not overflow because a result that cannot be represented by the resulting unsigned integer
type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting unsigned integer
type.

For ISO C(99), it is 6.2.5/9:

A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

Which means the result is guaranteed to be the same as SIZE_MAX - (sizeof(struct foo)) + 1.


In ISO 14882:2003 5.3.1.7:

[...] The negative of an unsigned
quantity is computed by subtracting
its value from 2n, where
n is the number of bits in
the pro- moted operand. The type of
the result is the type of the promoted
operand.

悸初 2024-08-06 19:40:33

http://msdn.microsoft.com/en-我们/库/wxxx8d2t%28VS.80%29.aspx

无符号数量的一元否定
通过减去该值来执行
2n 中的操作数,其中 n 是
对象中的位数
给定无符号类型。 (微软C++
在利用的处理器上运行
补码算术。 关于其他
处理器,否定算法
可能有所不同。)

换句话说,确切的行为将是特定于体系结构的。 如果我是你,我会避免使用这种奇怪的结构。

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

Unary negation of unsigned quantities
is performed by subtracting the value
of the operand from 2n, where n is the
number of bits in an object of the
given unsigned type. (Microsoft C++
runs on processors that utilize
two's-complement arithmetic. On other
processors, the algorithm for negation
can differ.)

In other words, the exact behavior will be architecture-specific. If I were you, I would avoid using such a weird construct.

一绘本一梦想 2024-08-06 19:40:33

我唯一能想到的是错得我头疼……

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;

溢出是一个功能!

The only thing I can think of is so wrong it makes my head hurt...

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;

Overflow is a feature!

独留℉清风醉 2024-08-06 19:40:33

对无符号数求反对于在整个字中传播 lsb 以形成后续按位运算的掩码非常有用。

negating an unsigned number is useful for propagating the lsb across the word to form a mask for subsequent bitwise operations.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文