套管指针(unit8_t到uint16_t)返回字节的反向表示

时间:2016-02-24 14:55:02

标签: c++ pointers casting

我正在尝试运行此代码:

#include <iostream>
#include <string>
#include <cstdint>
#include <array>

int main()
{
    std::array<std::uint8_t, 2> one_byte_array;
    one_byte_array[0] = 0xff;
    one_byte_array[1] = 0x00;
    auto ptr8 = one_byte_array.data();
    std::uint16_t* ptr16 = (std::uint16_t*)ptr8;
    std::cout << *ptr16;
    return 0
}

Live Demo

输出:

  

255

我认为应该输出:

  

65280

因为0xff代表新MSBs的{​​{1}}而word代表新0x00的{​​{1}}。我错过了什么?

4 个答案:

答案 0 :(得分:3)

您的演员表的行为未定义:这是因为类型不相关。

如果您想将两个uint8_t合并为一个uint16_t,请创建一个包含2个元素的前者的数组,并将memcpy加入{ {1}}。

不要考虑uint16_t unionuint16_t数组作为回读非联盟成员的行为你用来设置联合数据的那个也是 undefined 。)

答案 1 :(得分:2)

您违反了严格的别名规则。你不能这样做。至于小端英特尔CPU,这是你最不担心的事情。

答案 2 :(得分:1)

正如已经提到的其他答案和评论:为整数表示构建指针是未定义的行为,但您目击的是与主机endianess有关,主机endianess是主机如何解释一系列字节以形成更长的单词。

从字节缓冲区(在这种情况下为std::array<std::uint8_t, 2>)到实际数据被称为deserialization,并且最简单的方法来执行此主机endianess不知道(假设缓冲区是大端)是移位字节融入积分。有关浮动的可移植序列化,请参阅this answer

std::array<std::uint8_t, 2> one_byte_array;
one_byte_array[0] = 0xff;
one_byte_array[1] = 0x00;
uint16_t data = one_byte_array[0] << 8 | one_byte_array[1];

实际上,this answer已经更好地解释了它。

另一种方法是使用ntohs

std::array<std::uint8_t, 2> one_byte_array;
one_byte_array[0] = 0xff;
one_byte_array[1] = 0x00;
uint16_t data;
std::memcpy(&data, one_byte_array.data(), 2);
data = ntohs(data);

答案 3 :(得分:0)

要进行类似的转换,请通过联合键入-pin,以避免破坏严格的别名优化。见strict aliasing and type punning

重要的一句是:&#39;严格地说,读取与写入的联盟不同的联盟成员在ANSI / ISO C99中是未定义的,除了在类型 - 惩罚到char *的特殊情况下,类似以下示例:转换为char *。然而,这是一个非常普遍的习惯用语,并得到所有主要编译器的良好支持。实际上,以任何顺序阅读和写作任何工会成员都是可以接受的做法。&#39;

那些谈论UB的人可以坐在他们的象牙塔里,为我所关心的一切,阅读我联系的信息并学习一些东西。