C++ c++;将2个uint8\u t合并为一个uint16\u t不工作?

C++ c++;将2个uint8\u t合并为一个uint16\u t不工作?,c++,endianness,C++,Endianness,我有一段代码,它取2个uint8,然后放在彼此旁边,然后返回一个uint16。重点不是添加这两个变量,而是将它们放在一起并从中创建uint16。 我希望它能够工作的方式是,当第一个uint8_t为0,第二个uint8_t为1时,我希望uint16_t也为1。 然而,在我的代码中,情况并非如此。 这是我的代码: uint8_t *bytes = new uint8_t[2]; bytes[0] = 0; bytes[1] = 1; uint16_t out = *((uint16_t*)bytes

我有一段代码,它取2个uint8,然后放在彼此旁边,然后返回一个uint16。重点不是添加这两个变量,而是将它们放在一起并从中创建uint16。 我希望它能够工作的方式是,当第一个uint8_t为0,第二个uint8_t为1时,我希望uint16_t也为1。 然而,在我的代码中,情况并非如此。 这是我的代码:

uint8_t *bytes = new uint8_t[2];
bytes[0] = 0;
bytes[1] = 1;
uint16_t out = *((uint16_t*)bytes);
它应该将字节uint8\u t指针转换为uint16\u t指针,然后获取值。我希望该值为1,因为x86是little endian。但是它返回256。 将第一个字节设置为1,第二个字节设置为0,使其按预期工作。但是我想知道为什么我需要切换字节才能工作

谁能给我解释一下吗


谢谢

如果
p
是指向某个多字节值的指针,则:

  • “Little endian”表示
    p
    处的字节是最低有效字节,换句话说,它包含值的0-7位
  • “Big-endian”意味着
    p
    处的字节是最高有效字节,对于16位值,它将是位8-15
由于英特尔是小端,字节[0]包含
uint16\t
值的位0-7,字节[1]包含位8-15。由于您正在尝试设置位0,因此需要:

bytes[0] = 1; // Bits 0-7
bytes[1] = 0; // Bits 8-15

在小端系统中,小字节放在第一位。换句话说:低位字节放在偏移量0上,高位字节放在偏移量1上(依此类推)。因此:

uint8_t* bytes = new uint8_t[2];
bytes[0] = 1;
bytes[1] = 0;
uint16_t out = *((uint16_t*)bytes);
生成所需的
out
=1结果

但是,正如您所看到的,这很容易出错,因此一般来说,我建议您不要尝试将内容正确地放置在内存中,然后将其丢弃,而是执行以下操作:

uint16_t out = lowByte + (highByte << 8);
uint16\u t out=lowByte+(highByte
将它们移到右侧)


如果X包含位模式
xxxxxxxx
,Y包含位模式
yyyyyyy
,则
(X该地址没有
uint16\u t
或兼容对象,因此
*((uint16\u t*)字节的行为是未定义的

我希望该值为1,因为x86是小端,但它返回256

即使程序被固定为具有定义良好的行为,您的期望也是反向的。在little endian中,最低有效字节存储在最低地址中。因此,2字节值1存储为1,0,而不是0,1


endianess是否也会影响位在字节中的顺序

无法通过“地址”1访问位,因此没有结尾的概念。在转换为文本时,位通常显示在左边最重要,右边最少;就像十进制数字的数字一样。我不知道这在从右到左的书写系统中是否正确

1您可以使用位字段为位创建“虚拟地址”排序。位字段的顺序,即第一个位字段是最高有效位还是最低有效位,由实现定义,不一定与字节结束度相关


以下是将两个八位字节设置为
uint16\t
的正确方法。结果将取决于系统的端度:

// no need to complicate a simple example with dynamic allocation
uint16_t out;
// note that there is an exception in language rules that
// allows accessing any object through narrow (unsigned) char
// or std::byte pointers; thus following is well defined
std::byte* data = reinterpret_cast<std::byte*>(&out);
data[0] = 1;
data[1] = 0;
//无需将动态分配的简单示例复杂化
uint16_t out;
//请注意,语言规则中有一个例外:
//允许通过窄(无符号)字符访问任何对象
//或者std::字节指针;因此下面是定义良好的
std::byte*data=重新解释强制转换(&out);
数据[0]=1;
数据[1]=0;
请注意,假设输入为本机端通常不是一个好的选择,特别是当需要跨多个系统的兼容性时,例如通过网络通信或访问可能共享给其他系统的文件时


在这些情况下,通信协议或文件格式通常指定数据的特定端号,该端号可能与目标系统的本机端号相同,也可能与目标系统的本机端号不同。网络通信中的事实标准是使用大端号。可以使用位s将数据的特定端号转换为本机端号例如,如Frodyne的回答所示,移位。

您的代码工作正常,但您误解了如何读取“字节”

#包括
#包括
#包括
int main()
{
uint8_t*in=新uint8_t[2];
in[0]=3;
in[1]=1;
uint16_t out=*((uint16_t*)in);
标准::cout
用数字思考的一种方法是使用MSB和LSB顺序
其中MSB是最高位,LSB是最低位
小端机器

例如

(u)int32:  MSB:Bit 31 ...  LSB: Bit 0
(u)int16:  MSB:Bit 15 ...  LSB: Bit 0
(u)int8 :  MSB:Bit  7 ...  LSB: Bit 0

with your cast to a 16Bit value the Bytes will arrange like this

16Bit                <=  8Bit       8Bit
MSB     ...    LSB       BYTE[1]    BYTE[0]
Bit15          Bit0      Bit7 .. 0  Bit7 .. 0
0000 0001 0000 0000      0000 0001  0000 0000

which is 256 -> correct value.

(u)int32:MSB:位31…LSB:位0
(u) int16:MSB:位15…LSB:位0
(u) int8:MSB:位7…LSB:位0
将强制转换为16位值时,字节的排列方式如下
16位正确值。

你给这个问题贴上了“endianness”的标签。你到底不明白什么?因为endianness基本上就是答案。“Little endian”意思是
0xABCD
被安排为
0xCD,0xAB
。你混淆了这两种结尾吗?是的,我混淆了它们。认为小结尾是以小结尾的。是的,我讨厌这些名字。正是因为这个原因,我总是在脑子里把它们混在一起。为什么“结尾”意味着“第一个结尾”我无法理解。试着记住,大端是你用拉丁语系统(例如12345)写数字的方式(即对我们中的许多人来说,“正常”),然后从那里开始工作。谢谢!我混淆了端。我认为小端是以小端结尾的。(这可以解释名称)endianess是否也会影响字节中位的顺序?@Its-a-me-mario No。事实上,定义良好的行为需要
std::copy
(或等效文件)。或者从
uint16\u t
开始,然后通过
uint8\u t*
写入。然后只需打印basta
(u)int32:  MSB:Bit 31 ...  LSB: Bit 0
(u)int16:  MSB:Bit 15 ...  LSB: Bit 0
(u)int8 :  MSB:Bit  7 ...  LSB: Bit 0

with your cast to a 16Bit value the Bytes will arrange like this

16Bit                <=  8Bit       8Bit
MSB     ...    LSB       BYTE[1]    BYTE[0]
Bit15          Bit0      Bit7 .. 0  Bit7 .. 0
0000 0001 0000 0000      0000 0001  0000 0000

which is 256 -> correct value.