【问题标题】:Why is −1 > sizeof(int)?为什么-1 > sizeof(int)?
【发布时间】:2011-03-07 05:37:49
【问题描述】:

考虑以下代码:

template<bool> class StaticAssert;
template<> class StaticAssert<true> {};
StaticAssert< (-1 < sizeof(int)) > xyz1; // Compile error
StaticAssert< (-1 > sizeof(int)) > xyz2; // OK

为什么-1 &gt; sizeof(int) 是真的?

  1. 是不是真的-1被提升为unsigned(-1)然后unsigned(-1) &gt; sizeof(int)
  2. 如果 sizeof(int) 为 4,-1 &gt; sizeof(int) 是否等于 -1 &gt; size_t(4)。如果是这样,为什么 -1 &gt; size_t(4) 为 false?

这是符合 C++ 标准的吗?

【问题讨论】:

    标签: c++ type-conversion sizeof unsigned modular


    【解决方案1】:

    以下是标准(ISO 14882)如何解释 abort -1 > sizeof(int)

    关系运算符 `>' 在 5.9 (expr.rel/2) 中定义

    通常的算术转换是 在算术操作数上执行或 枚举类型。 ...

    常用的算术转换定义在 5 (expr/9)

    ...该模式称为通常的算术转换,定义如下:

    • 如果任一操作数的类型为 long 双倍,...
    • 否则,如果任一操作数是双精度数,...
    • 否则,如果任一操作数为浮点数,...
    • 否则,应对两个操作数执行积分提升。
    • ...

    积分促销在 4.5 (conv.prom/1) 中定义

    char 类型的右值,带符号的 char, unsigned char、short int 或 unsigned short int 可以转换为 如果 int 可以,则为 int 类型的右值 表示源的所有值 类型;否则,源右值可以 被转换为类型的右值 无符号整数。

    sizeof的结果定义在5.3.3 (expr.sizeof/6)

    结果是一个类型的常量 尺寸_t

    size_t 是在 C 标准 (ISO 9899) 中定义的,它是无符号整数类型

    所以对于-1 &gt; sizeof(int),> 触发通常的算术转换。通常的算术转换将 -1 转换为 unsigned int,因为 int 不能表示 size_t 的所有值。 -1 成为一个非常大的数字,取决于平台。所以-1 &gt; sizeof(int)true

    【讨论】:

    • 这可能只是一个错字,但size_tan 无符号整数类型,并且不一定是 int 不能代表所有size_t 的值(size_t 可能是 unsigned short),尽管它显然不能在提问者的平台上。
    • (unsigned T)-1 不仅仅是一个大值,它是unsigned T 可以容纳的最大值。
    • 我很清楚标准允许什么。 :) -1 永远是最大的,请阅读转换规则。或者这个stackoverflow.com/questions/809227/…
    • @GMan 感谢您的帮助。我误解了标准中的描述。 (删除错误评论)
    【解决方案2】:

    因为 unsigned 比有符号更强,并且 -1 从 size_t 转换为无符号值,所以实际上是 -1 == 0xFFFFFFFF &gt; 4

    这就是它应该按照 C++ 标准的工作方式

    【讨论】:

    • 编译器不会针对这种情况发出警告吗?
    • @kriss - 不同的编译器发出不同的警告。也可以通过编译器命令行选项和/或源代码中的编译指示来抑制警告;和/或然后可以被程序员忽略。
    • 仅当使用 One's 或 Two's 补码时(此处不确定)。
    • @rubenvb:没关系:unsigned(-1) == UINT_MAX 按照标准,无处不在。
    • @Artyom:unsigned is stronger then signedstronger 是什么?标准没有定义这个术语。
    【解决方案3】:

    因为 -1 被强制转换为 size_t,这是一个无符号数据类型 - 所以 (size_t)-1 == 4294967295(在 32 位系统上)肯定大于 4

    如果您将-Wall 添加到 gcc 设置中,例如,您会收到一条警告,提示您正在比较有符号和无符号数据类型

    【讨论】:

    • 假设 sizeof(size_t) >= sizeof(int) - IOW:它是否标准化真的安全吗?
    【解决方案4】:

    简单而悲伤。在 C/C++ 中:

    1. 大多数时候,无符号整数类型具有模整数的语义(它们表示等价类)
    2. 无符号整数类型的比较具有通常整数排序的语义,因此1U &lt; 2U(IOW 0U 是最小的unsigned 值)
    3. sizeof 的类型为 size_t
    4. size_t 是无符号整数类型
    5. 第 (1) 点暗示涉及有符号和无符号整数的混合算术计算是在无符号模算术中完成的:这是不违反“无符号平均模数”规则的唯一可能性。将整数转换为与其等效的整数的等价类是微不足道的。 (反之则需要选择一个整数来表示等价类。)
    6. 第 (5) 点意味着-1 &lt; 1U 被解释为unsigned(-1) &lt; 1U,而unsigned(-1) = - 1U,显然- 1U &lt; 1U,所以-1 &lt; 1U 为真。
    7. 点 (1,3,4) 暗示 sizeof something (大部分)充当等效类 (!!!)。
    8. 所有这些都暗示-1 &lt; sizeof something

    结论:这是继承自 C 的设计错误。

    规则:

    仅将无符号类型用于模运算、位操作(&amp;|^&lt;&lt;&gt;&gt;~ 运算符)、字节操作(unsigned char 表示“字节”在 C/C++ 中)和字符(unsigned char 表示 C/C++ 中的字符)。

    不要使用无符号类型进行算术运算。

    如果函数需要一个永远不应为负的整数值,则取一个有符号整数,并可选择在函数中检查该值是否在范围内。

    【讨论】:

    • 我发现第(6)点有点混乱,也许==包含在unsigned(-1) = - 1U会更好
    猜你喜欢
    • 2013-09-24
    • 2012-06-14
    • 1970-01-01
    • 2014-08-19
    • 2011-11-04
    • 1970-01-01
    • 2011-01-16
    • 2014-08-13
    相关资源
    最近更新 更多