【问题标题】:Are bitwise operations defined and portable on signed fixed-width integers?是否在有符号的固定宽度整数上定义和可移植按位运算?
【发布时间】:2020-04-24 14:02:17
【问题描述】:

我的理解是,对常规 ol' short/int/long 类型的某些按位运算要么是依赖于实现的( | & ~ >> ),要么是未定义的(

但是,C99 引入了固定宽度的整数类型,并且明确地将它们定义为没有填充位的二进制补码精确位。

这是否意味着所有按位运算对于这些类型在提供它们的平台之间都是明确定义和可移植的?

例如,这个 Works on My Machine™,但它是否保证可以工作?

#include <inttypes.h>
#include <stdio.h>

int main() {
  uint16_t a = 0xffff;
  int16_t b = *(int16_t*)(&a);

  printf("%" PRId16 "\n", b);

  // Prints '-1'

  b <<= 4;

  printf("%" PRId16 "\n", b); 

  // Prints '-16'

  return 0;
}

【问题讨论】:

  • 请注意,x &lt;&lt; n 仅在 x &lt; 0n &lt; 0n &gt;= CHAR_BIT * sizeof x 时是未定义的行为。
  • @MarcoBonelli 不同意is undefined behavior only if ....。它也是带有符号正数x 的 UB,并且移位后的值无法在结果类型中表示。
  • @chux-ReinstateMonica 呵呵,你是对的,忘记了操作数可以有不同类型的事实。哦,男孩,每个角落后面真的有UB......

标签: c language-lawyer


【解决方案1】:

使用固定宽度类型并不能保证免受与位移相关的undefined behavior 的影响。 C standard 第 7.20.1.1 节关于精确宽度整数类型的状态:

1 typedef 名称intN_t 指定宽度为 N、无填充位和二进制补码的有符号整数类型 表示。因此,int8_t 表示这种有符号整数类型 宽度正好是 8 位。

2 typedef 名称uintN_t 指定一个宽度为 N 且没有填充位的无符号整数类型。因此,uint24_t 表示 这样的无符号整数类型,宽度正好是 24 位。

3 这些类型是可选的。但是,如果实现提供了宽度为 8、16、32 或 64 位的整数类型, 没有填充位,并且(对于有符号类型)具有 二进制补码表示,它应定义相应的 typedef 名称。

这里没有提到对这些类型的位移操作行为的特殊处理。

这里的一个重要方面是整数提升。对于小于int 的固定宽度类型,在应用于大多数操作数之前,它们将首先提升为int(不是int16_tint32_t)。然后你正在处理潜在的未定义行为。

例如,假设一个 32 位 int,此代码表现出未定义的行为:

uint24_t x = 0xffffff;
uint24_t y = x << 8;

因为在表达式x &lt;&lt; 8 中,x 的值被提升为int,然后移位导致一个位被移入该值的符号位。

【讨论】:

    猜你喜欢
    • 2016-01-19
    • 1970-01-01
    • 1970-01-01
    • 2023-04-11
    • 2019-05-20
    • 1970-01-01
    • 2012-11-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多