C++ 无ntohs的Endianness交换

C++ 无ntohs的Endianness交换,c++,endianness,C++,Endianness,我正在编写一个ELF分析器,但是我在正确转换endianness时遇到了一些问题。我有一些函数来确定分析器的endianness和对象文件的endianness 基本上,有四种可能的情况: 在big-endian对象文件上运行的big-endian编译分析器 什么都不需要转换 一个大端编译的分析器在一个小端对象文件上运行 字节顺序需要交换,但ntohs/l()和htons/l()都是big-endian机器上的空宏,因此它们不会交换字节顺序这就是问题所在 在大端对象文件上运行的小端编译分

我正在编写一个ELF分析器,但是我在正确转换endianness时遇到了一些问题。我有一些函数来确定分析器的endianness和对象文件的endianness

基本上,有四种可能的情况:

  • 在big-endian对象文件上运行的big-endian编译分析器
    • 什么都不需要转换
  • 一个大端编译的分析器在一个小端对象文件上运行
    • 字节顺序需要交换,但ntohs/l()和htons/l()都是big-endian机器上的空宏,因此它们不会交换字节顺序这就是问题所在
  • 在大端对象文件上运行的小端编译分析器
    • 字节顺序需要交换,因此使用htons()交换字节顺序
  • 小端编译分析器在小端对象文件上运行。
    • 什么都不需要转换
  • 有没有一个函数可以用来显式交换字节顺序/更改尾数,因为ntohs/l()和htons/l()考虑了主机的尾数,有时不进行转换?或者我需要在Linux中的
    endian.h
    中查找/编写自己的交换字节顺序函数吗?

    ,该函数允许在任意endian之间转换:

    uint16_t htobe16(uint16_t host_16bits);
    uint16_t htole16(uint16_t host_16bits);
    uint16_t be16toh(uint16_t big_endian_16bits);
    uint16_t le16toh(uint16_t little_endian_16bits);
    
    uint32_t htobe32(uint32_t host_32bits);
    uint32_t htole32(uint32_t host_32bits);
    uint32_t be32toh(uint32_t big_endian_32bits);
    uint32_t le32toh(uint32_t little_endian_32bits);
    
    uint64_t htobe64(uint64_t host_64bits);
    uint64_t htole64(uint64_t host_64bits);
    uint64_t be64toh(uint64_t big_endian_64bits);
    uint64_t le64toh(uint64_t little_endian_64bits);
    
    编辑,不太可靠的解决方案。您可以使用union以任何顺序访问字节。非常方便:

    union {
        short number;
        char bytes[sizeof(number)];
    };
    
    我是否需要查找/编写自己的交换字节顺序函数


    是的,你知道。但是,为了简单起见,我想让您看看这个问题:它给出了编译器特定字节顺序交换函数的列表,以及字节顺序交换函数的一些实现。

    ntoh函数可以在不仅仅是大尾端和小尾端之间进行交换。有些系统也是“中间端”系统,字节被置乱,而不是以某种方式排序


    无论如何,如果您关心的只是大的和小的尾端,那么您需要知道的就是主机和对象文件的尾端是否不同。您将拥有自己的函数,该函数无条件交换字节顺序,并且您将根据是否调用该函数来决定是否调用该函数。
    host\u endianess()==objectfile\u endianess()

    如果我考虑在windows或linux上工作的跨平台解决方案,我将编写如下内容:

    #include <algorithm>
    
    // dataSize is the number of bytes to convert.
    char le[dataSize];// little-endian
    char be[dataSize];// big-endian
    
    // Fill contents in le here...
    std::reverse_copy(le, le + dataSize, be);
    
    #包括
    //dataSize是要转换的字节数。
    字符[数据大小];//小恩迪亚
    char be[dataSize];//大端
    //在这里填写le的内容。。。
    std::反向拷贝(le,le+数据大小,be);
    
    我认为值得在这里发表一篇由Rob Pyke(Go的作者之一)撰写的文章

    如果你做得对,也就是说,你不必对你的平台字节顺序做任何假设,那么它就会起作用。您需要关心的是ELF格式的文件是采用小端还是大端模式

    从文章中:

    假设您的数据流有一个小的endian编码的32位整数。下面是如何提取它(假设为无符号字节):


    <代码> >(数据[0 ],C++中技术上未定义的行为。但是,我们如何知道正确的顺序?”BPopssOPoP知道,当他想交换字节时,我编辑了我的答案,以揭示更合适的解决方案。这真的很有用,但不幸的是(我的错不说)我的程序需要工作在*NIX机器上,可能没有这个。(读:solaris)可用。Upvote是最简单的,但我接受了另一个,因为它是最可移植的。如果您首先从一个字开始,AFAIK编译器将只使用优化的字节顺序交换。@AndrewDunn:很可能,但像往常一样,测量两次,优化一次。
    i = (data[0]<<0) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);
    
    i = (data[3]<<0) | (data[2]<<8) | (data[1]<<16) | (data[0]<<24);