【问题标题】:Truncating an int to char - is it defined?将 int 截断为 char - 是否已定义?
【发布时间】:2011-05-04 10:21:44
【问题描述】:
unsigned char a, b;
b = something();
a = ~b;

一个静态分析器抱怨最后一行被截断,大概是因为b 在其位被翻转之前被提升为 int 并且结果将是 int 类型。

我只对提升的 int 的最后一个字节感兴趣 - 如果 b 是 0x55,我需要 a 是 0xAA。我的问题是,C 规范是否说明了截断是如何发生的,还是实现定义/未定义?是否保证a 将始终获得我期望的值,还是在符合标准的平台上会出错?

当然,在分配之前强制转换结果会使静态分析器静音,但我想知道首先忽略此警告是否安全。

【问题讨论】:

  • 我会说这是一个虚假的警告。我刚刚通过 clang 静态分析器运行了你的代码,它没有抱怨。 something()的返回类型是什么
  • @Jeremy 这是一个示例代码来说明场景。真正的代码类似于mask1[0] = ~mask2[0];,其中两者都是 unsigned char 类型的数组。显然,我的静态分析器不如 clang 聪明 :)

标签: c bitwise-operators integer-promotion


【解决方案1】:

C 标准为无符号类型指定了这一点:

涉及无符号的计算 操作数永远不会溢出,因为 无法表示的结果 得到的无符号整数类型是 减少模数是一 大于最大值 可以用结果来表示 输入。

在这种情况下,如果你的unsigned char是8位,则意味着结果会以256为模减少,这意味着如果b0x55a确实会以0xAA结束.

但请注意,如果unsigned char 大于 8 位(这是完全合法的),您将得到不同的结果。为确保您能以便携方式获得 0xAA 作为结果,您可以使用:

a = ~b & 0xff;

(按位和应该在unsigned char 为8位的平台上进行优化)。

另请注意,如果您使用有符号类型,则结果是实现定义的。

【讨论】:

  • 我担心它不会溢出(因为这里的操作员是~) - 可以将 0xFFFFFFAA 截断为 char 导致说 0xFF (msb) 而不是 0xAA (lsb) 吗?跨度>
  • 不,归约始终是“模 2^n”操作,其中 n 是 char 中的位数。字节顺序无关紧要
  • @Amarghosh 不,无论字节顺序如何,它都会使用最低有效字节。
  • @Amarghosh:来自 的引用部分“因为无法表示的结果......” 仍然相关。由于值 0xFFFFFFAA 不能用 8 位 unsigned char 表示,它将以 256 为模减少 - 这导致 0xAA
  • 使用uint8_t 并没有真正的帮助,因为除非CHAR_BIT 为8,否则它不会存在。仅使用#if#error 也可以。
【解决方案2】:

截断如C99 Standard 的 6.3.1.3/2 中所述发生

...如果新类型是无符号的,则在新类型可以表示的最大值的基础上反复加减1,直到值在新类型的范围内。

p>

CHAR_BIT == 8、sizeof (unsigned char) == 1、sizeof (int) == 4 的示例

因此,0x55​​ 转换为 int,转换为 0x00000055,然后取反为 0xFFFFFFAA,然后

0xFFFFFFAA + 0x00000100 /* UCHAR_MAX + 1 */ ------------ 0xFFFFFEAA ...重复很多很多次... 0x000000AA

或者,正如你所期望的那样,0xAA

【讨论】:

  • Errrr ...这个例子是相当错误的LOL,但你明白了:)
【解决方案3】:

它将按照您的意愿行事。转换值是安全的。

【讨论】:

    【解决方案4】:

    这个特定的代码示例是安全的。但是有理由警告不要随意使用 ~ 运算符。

    这背后的原因是 ~ 在小整数变量上是更复杂表达式中的潜在错误,因为 C 中的隐式整数提升。想象一下,如果你有一个像

    这样的表达式

    a = ~b >> 4;

    它不会像预期的那样变为零。

    如果您的静态分析器设置为包含 MISRA-C,例如,您将针对每个 ~ 运算符收到此警告,因为 MISRA 强制将小整数类型上的任何操作的结果显式类型转换为预期的类型 unsigned char在这种情况下。

    【讨论】:

      【解决方案5】:

      让我们以 Win32 机器为例。
      整数是 4 个字节,将其转换为 char 的结果就像删除了剩下的 3 个字节一样。

      当您将 char 转换为 char 时,它被提升为什么并不重要。
      ~b will add 3 bytes at the left change 0s to 1 and then remove... It does not affect your one right byte.

      相同的概念将适用于不同的架构(无论是 16 位还是 64 位机器)

      假设它是小端的

      【讨论】:

      • 我正在尝试在这里写下这个概念......假设它是 32 位机器......就概念而言,64 位机器或不同的架构不会有任何区别。3
      • @Mayank:为了其他可能在未来阅读您的答案的 SO 用户,重要的是它不包含错误信息
      • @Paul:感谢您的评论。以后我会处理的
      • @Mayank:您可能可以编辑上述答案,使其更准确和普遍适用
      • @Mayank:这有点好——不过我会删除关于小端序的最后一行,因为它无关紧要。
      猜你喜欢
      • 2013-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-03
      • 1970-01-01
      • 1970-01-01
      • 2010-09-10
      相关资源
      最近更新 更多