【问题标题】:Should I use a bit mask when truncating uint64_t to uint8_t[i]?将 uint64_t 截断为 uint8_t[i] 时是否应该使用位掩码?
【发布时间】:2016-04-06 01:16:17
【问题描述】:

如果我有一个大的 int,比如说一个 uint64_t,和一个 uint8_t 数组,例如:

uint64_t large = 12345678901234567890;
uint8_t small[5];

我想将uint64_t 的8 个最低有效位复制到uint8_t 数组的一个元素中,只使用它是否安全:

small[3] = large;

或者我应该使用位掩码:

small[3] = large & 255;

即是否有任何情况下大 int 的其余部分可能会以某种方式溢出到数组的其他元素中?

【问题讨论】:

  • 绝对安全。一些编译器会发出警告(恕我直言,这是一个虚假的警告,因为代码是正确的)所以使用掩码没有害处。如果你想记录意图,你可以使用static_cast<uint8_t>(large);
  • 我会从“小”中删除数组,因为它在这个问题上没有任何作用。
  • @xvan 实际上是数组让我担心。使用单个 uint8_t,我会毫不犹豫地写 small = large
  • (large & 255) 确实具有使人类读者非常清楚的有益效果,即您确实确实打算丢弃除最低 8 位以外的所有位,并且不只是意外失败请注意,您正在将 64 位值分配给 8 位变量。 static_cast(large & 0xFF) 可能会更好。

标签: c++ arrays int type-conversion bit-manipulation


【解决方案1】:

它肯定不会导致数据处理不正确。但是,某些编译器可能会生成警告消息。

有两种方法可以避免这些。

你可以转换你的变量:

(uint8_t)large

或者您可以禁用警告:

#pragma warning(disable:4503)

我建议强制转换该变量,因为隐藏编译器警告可能会使您无法发现实际问题,因此不是最佳做法。

【讨论】:

  • 请注意,强制转换,尤其是 C 风格的强制转换,也会隐藏警告和错误。只要警告仅在已知安全的范围内被禁用,强制转换就没有道德上的优越性。
  • static_cast 可能更明确,但对于整数数据类型,C 风格的转换就足够了。
  • 我并不是说它们不起作用,我是说它们可以像消除警告一样有效地隐藏问题。 C 风格的强制转换可以做比static_cast 更危险的事情,并防止编译器抱怨,这就是它如此危险的原因。在这种情况下,这并不是说它不好,但是那些首先使用强制转换来关闭编译器的人最终会不小心尝试将 ints 取消引用为指针和其他可怕的事情。我特别反对你的说法,即原则上强制转换比局部警告抑制更好。
【解决方案2】:

这是绝对安全

small[3] = large;

并且在 [conv.integral] 中明确描述了这样的转换:

如果目标类型是无符号的,则结果值是与源一致的最小无符号整数 整数(模 2n 其中 n 是用于表示无符号类型的位数)。

也就是说,这四个语句都保证在small[3]中得到相同的值:

small[3] = large;
small[3] = large % 256;
small[3] = large & 255;
small[3] = static_cast<uint8_t>(large);

没有功能上的理由去做%&amp; 或自己转换,但如果你想无论如何我会感到惊讶,如果编译器没有为所有四个生成相同的代码(gcc 和 clang 做) .

一个区别是,如果您使用 -Wconversion 之类的东西进行编译,这会导致它发出警告(这有时可能是有益的)。在这种情况下,你会想要做演员。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多