【问题标题】:Type of integer literals and ~ in CC 中整数文字和 ~ 的类型
【发布时间】:2015-04-17 03:46:59
【问题描述】:

我是 C 初学者,我对 C 答案簿中的以下示例感到困惑。

在系统上查找 unsigned long long 大小的一种方法是键入:

printf("%llu", (unsigned long long) ~0);

我不知道为什么这种语法有效?

在我的系统上,int 是 32 位,long long 是 64 位。
我的预期是,由于0 是一个整数类型的常量,~0 计算一个 32 位整数的否定,然后由 cast 运算符转换为一个 unsigned long long。结果应该是 232 - 1 。

不知何故,~ 运算符似乎已经知道它应该作用于 64 位?
编译器是否将此指令解释为 printf("%llu", ~(unsigned long long)0); ?这听起来不对,因为演员表和~ 具有相同的优先级。

【问题讨论】:

    标签: c integer bitwise-operators literals


    【解决方案1】:

    根据 N1570 委员会草案:

    6.5.3.3 Unary arithmetic operators

    1. ~ 运算符的结果是它的 按位补码 (提升)操作数(即,结果中的每一位都被设置当且仅 如果未设置转换后的操作数中的相应位)。这 对操作数执行整数提升,结果有 提升的类型。如果提升的类型是“无符号类型,则 表达式 ~E 等价于可表示的最大值 键入减 E"。

    §6.2.6.2 Language 45:

    (一个补码)。其中哪一个适用是实现定义的,无论是符号位为 1 且所有值位为零(对于前两个)的值,还是符号位和所有值位为 1(对于 1'补),是陷阱表示或正常值。在符号和幅度以及反码的情况下,如果这种表示是正常值,则称为负零。

    因此,代码的行为:

    printf("%llu", (unsigned long long) ~0);
    

    在某些机器上,实现定义和未定义 - 与预期不同 - 取决于机器中整数的内部表示。

    根据第 6.5.3.3 节,批准的代码编写方式是:

    printf("%llu", (unsigned long long) ~0u);
    

    此外,~0u 的类型是 unsigned int,当您将其转换为 unsigned long long int 时,其格式字符串为 llu。使用格式字符串%u 打印~0u

    要了解类型转换的基本概念,您可以阅读:What exactly is a type cast in C/C++?

    【讨论】:

      【解决方案2】:

      不知何故,看起来 ~ 运算符已经知道它应该作用于 64 位?

      不是~ 运算符,而是演员表。以下是根据标准进行整数转换的方法:

      6.3.1.3 有符号和无符号整数

      • 当整数类型的值转换为_Bool以外的其他整数类型时,如果该值可以用新类型表示,则保持不变。
      • 否则,如果新类型是无符号的,则在新类型可以表示的最大值的基础上反复加减一,直到该值在新类型的范围内。
      • 否则,新类型是有符号的,值不能在其中表示;结果是实现定义的,或者引发了实现定义的信号。

      有符号的int~0 的值对应于具有负值补码表示的系统上的-1。它不能用unsigned long long 表示,因此第一个要点不适用。

      第二个要点确实适用:新类型是无符号的,因此将unsigned long longMAX 添加到-1 一次以将结果放入unsigned long long 的范围内。这与将 -1 符号扩展为 64 位的效果相同。

      【讨论】:

      • ~0 的值取决于实现中的签名表示。 ~0 不同于 -1 在二进制补码以外的表示形式。
      • 所以(unsigned long long)~0u 会发生预期的行为,对吧?
      • @Quentin:这始终取决于您的期望。避免这个,因为它太依赖于实现了。
      【解决方案3】:

      0 是一个int

      ~0 仍然是int,即值-1

      int 转换为 unsigned long long 只是为了匹配 printf 期望的类型与转换 llu

      但是,-1 扩展 unsigned long long 的值对于 4 字节 int 应该是 0xffffffff,对于 8 byte int 应该是 0xffffffffffffffff。

      【讨论】:

        【解决方案4】:

        0 的类型是 int,而不是 unsigned int。因此,~0 将(在使用二进制补码整数表示的机器上,这就是今天所使用的全部)为 -1,而不是 232 - 1。

        假设 64 位 unsigned long long(unsigned long long) -1-1 模 264,即 264 - 1。

        【讨论】:

        • 不应该是实现定义,不确定(将有符号值转换为更长的无符号类型)?是的,在真正的普通 2s 补码机器上。在这种情况下,它可能会使用最自然的可用指令来扩大值,这可能不是符号扩展。
        • @Wintermute 你的意思是:0 的类型是 signed int 而不是 unsigned int ... ?
        • @umlcat intsigned int
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多