C++ c++;将2个uint8\u t合并为一个uint16\u t不工作?
我有一段代码,它取2个uint8,然后放在彼此旁边,然后返回一个uint16。重点不是添加这两个变量,而是将它们放在一起并从中创建uint16。 我希望它能够工作的方式是,当第一个uint8_t为0,第二个uint8_t为1时,我希望uint16_t也为1。 然而,在我的代码中,情况并非如此。 这是我的代码: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
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”表示
处的字节是最低有效字节,换句话说,它包含值的0-7位p
- “Big-endian”意味着
处的字节是最高有效字节,对于16位值,它将是位8-15p
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.