【问题标题】:shifting bits in a std::uint8_t [duplicate]在 std::uint8_t 中移位 [重复]
【发布时间】:2020-08-19 10:39:46
【问题描述】:

我正在尝试将多个索引打包成一个字节(由GIF format 定义):

std::uint8_t global_color_table_flag;    // bit  [0]
std::uint8_t color_resolution;           // bits [1-3]
std::uint8_t sort_flag;                  // bit  [4]
std::uint8_t global_color_table_size;    // bits [5-7]

我想用

std::uint8_t field = (global_color_table_flag << 7) |
                     (color_resolution << 4) | (sort_flag << 3) |
                     (global_color_table_size);

但是左移运算符&lt;&lt; 将我的std::uint8_t 提升为int 并且编译器抱怨(-Werror)。为什么呢?在int 上使用它不会将其提升为更大的int。如果您不正确地使用它,那只是UB。为什么std::uint8_t 有什么不同?

如果我使用std::byte,则行为符合预期。但是,由于上面提到的问题,代码相当难看:

std::byte global_color_table_flag_byte{global_color_table_flag};
global_color_table_flag_byte <<= 7;

std::byte color_resolution_byte{color_resolution};
color_resolution_byte <<= 4;

std::byte sort_flag_byte{sort_flag};
sort_flag_byte <<= 3;

std::byte global_color_table_size_byte{global_color_table_size};

std::byte packed_field = global_color_table_flag_byte |
                         color_resolution_byte | sort_flag_byte |
                         global_color_table_size_byte;

file_stream << std::to_integer<std::uint8_t>(packed_field);

有更好的方法吗?作为一个附带问题,为什么我不能将我的std::byte 写入我的二进制流?我认为这种类型的全部意义在于促进对此类流的操作。

【问题讨论】:

标签: c++ bit-manipulation


【解决方案1】:

但左移运算符

因为您启用了一些编译器选项,在这种情况下会发出警告。

为什么移位运算符在 int 和 std::uint8_t 上的工作方式不同。

因为std::uint8_t 是比int 更小的类型,因此它被提升。这对于所有小于int 的类型和所有算术运算符都是一样的,而不仅仅是位移。

有更好的方法吗?

您可以将编译器选项更改为不对正确的表达式发出警告。

或者您可以根据编译器警告的内容对表达式进行一些更改。在不知道警告的情况下,我无法更具体。

我添加了所有警告

这通常不是很有用。使用-Wall 很好,但它不会启用所有警告是有原因的。从中排除的许多警告选项会适得其反,有误报,或者只是用于调试复杂程序的含义而不是告知问题。

为什么我不能直接将 std::byte 写入二进制流?

将类型添加到语言中的提案没有为字符流提出额外的重载。该提案没有包括做出这种选择的理由。但我怀疑这是为了保持最小的变化。不知道组委会有没有讨论过。

【讨论】:

  • 谢谢,但我不是在问为什么编译器会抱怨(-> 我添加了所有警告 + Werror),而是为什么位移运算符在 intstd::uint8_t 上的工作方式不同。
  • @Touloudou 查看已编辑的答案。
  • 就是这样,uint64_t 上的左移会返回 uint64_t。同样,uint32_t 上的左移返回 uint32_t。小于该值的所有内容(uint8_tuint16_t)都将提升为 int。我不明白这里的推理。
  • @Touloudou 在您的系统上,uint64_tuint32_t 不小于int,因此当用作算术运算符的操作数时,它们不会提升为int。正如我在答案中解释的那样,只提升较小的整数类型。
  • @Touloudou 他们只是决定不改变 C 所做的事情。我不知道他们是否考虑过改变它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-05-10
  • 2016-08-30
  • 1970-01-01
  • 2020-12-09
  • 1970-01-01
  • 2017-11-24
  • 1970-01-01
相关资源
最近更新 更多