【问题标题】:How do you concatenate 4 UINT8 variables into one UINT32 variable?如何将 4 个 UINT8 变量连接成一个 UINT32 变量?
【发布时间】:2017-02-20 02:00:38
【问题描述】:

我有以下UINT8 变量:

UINT8 var1 = 0b00000001; //0000 0001
UINT8 var2 = 0b00000011; //0000 0011
UINT8 var3 = 0b00000111; //0000 0111
UINT8 var4 = 0b00001111; //0000 1111

我想将这四个UINT8 变量打包成一个UINT32 变量,其值如下:

UINT32 var1 = 0b00000001000000110000011100001111; //00000001 00000011 00000111 00001111

以下代码会正确且安全地执行此操作吗?

UINT32 var1 = (var1<<24) + (var2<<16) + (var3<<8) + var4;

【问题讨论】:

  • 您似乎认为00000001 等是二进制文字。您使用的是哪个 C++ 编译器?
  • UINT8UINT32 不是标准类型,因此您需要告诉我们它们的实际定义是什么。
  • 不,它不会,因为var2 = 00000011 的值是 9,而不是 3,因为前导 0 表示八进制表示法
  • 被几个人暗示过,但没有直接说出来。从 VS 2015 预览版(以及一段时间的 GCC)开始,您可以将二进制文字写为 UINT8 var1 = 0b00000001。否则,你不能。最简单的可能是UINT8 var2 =3; // 0000 0011。其他解决方案:stackoverflow.com/questions/2611764/…
  • @M.A.Kishawy 为什么不试试呢?

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


【解决方案1】:

简短回答,是的

我不会担心您是如何编写二进制数的。我将以十六进制输入它们,让您通过这个相关的 SO 问题查找二进制表示:Can I use a binary literal in C or C++?

#include "stdafx.h"   // you are using devstudio
#include <Windows.h>  // you are using windows types
#include <iostream>   // I print out the result
#include <bitset>     // I use bitset to print the binary string

int main()
{
    UINT8 var1 = 0x01; //0000 0001
    UINT8 var2 = 0x03; //0000 0011
    UINT8 var3 = 0x07; //0000 0111
    UINT8 var4 = 0x0F; //0000 1111

    UINT32 bigvar = (var1 << 24) + (var2 << 16) + (var3 << 8) + var4;
    std::cout << std::bitset<32>(bigvar) << std::endl;
}

你的数学是正确和安全的。字节是独立声明的,因此您不必担心字节顺序。这些类型都是无符号的,因此符号位没有 UB 问题。移位都符合正确的位数,因此不会溢出。我生成了:

00000001000000110000011100001111

或者,您可以将 32 位整数读取为 4 个字节,并重新构建 32 位数字,但这不具有可移植性,因为有时数字以相反的顺序存储。例如,在 TIFF 中,您读入一个标头值,该值告诉您是先放 var1 并向上计数,还是先放 var4 并向下计数。在将一堆字节组合成一个更大的整数类型的几乎所有实际应用中,您必须注意字节顺序。查找 big-endian 和 little-endian 了解更多信息。

【讨论】:

  • “你的数学是正确和安全的。”不,不是。 var1 &lt;&lt; 24 可能是 UB。
  • 我必须调查一下。我有类似于 tiff 操作库中的生产代码。什么时候会失败?
  • 它通过转移到符号位为所有var1 &gt; 127 调用UB(假设int 在您的平台上是32 位)。
  • 24 已签名。
  • 原来我错了,结果只是实现定义,在大多数平台上(即那些实现 2s 补整数数学的平台,如 gcc、clang、icc、MSVC..),我们总是会得到正确的结果。然而,发生的事情比你意识到的要多。对于初学者,var1 &lt;&lt; 24 等价于 int(var1) &lt;&lt; 24,即您的 LHS 签名,但 5.8/2 为我们修复了溢出问题。如果您想查看详细信息,请随时提出新问题。猴子链接的问题的答案也解释了。无论如何,已删除反对票。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-15
  • 1970-01-01
  • 1970-01-01
  • 2014-10-03
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
相关资源
最近更新 更多