我正在编写一个ELF分析器,但是我在转换字节顺序时遇到了一些麻烦。我有函数来确定分析器的字节顺序和目标文件的endiannness。
基本上,有四种可能的情况:
是否有一个函数可用于显式交换字节顺序/更改字节顺序,因为ntohs / l()和htons / l()会考虑主机的字节序,有时不会转换?或者我是否需要查找/编写自己的交换字节顺序函数?
答案 0 :(得分:9)
我认为值得提出The Byte Order Fallacy文章,由Rob Pyke(Go的作者之一)。
如果你做得对 - 即你不假设关于你的平台字节顺序的任何事情 - 那么它就会起作用。您需要关心的是ELF格式文件是否在 Little Endian 或 Big Endian 模式下。
来自文章:
假设您的数据流具有小端编码的32位整数。以下是如何提取它(假设无符号字节):
i = (data[0]<<0) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);
如果它是big-endian,这是如何提取它:
i = (data[3]<<0) | (data[2]<<8) | (data[1]<<16) | (data[0]<<24);
让编译器担心优化它。
答案 1 :(得分:7)
在endian.h
中的Linux there are several conversion functions中,允许在任意字节序之间进行转换:
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)];
};
答案 2 :(得分:3)
我是否需要查找/编写自己的交换字节顺序功能?
是的,你这样做。但是,为了方便起见,我向您推荐这个问题:How do I convert between big-endian and little-endian values in C++?给出了编译器特定字节顺序交换函数的列表,以及字节顺序交换函数的一些实现。
答案 3 :(得分:1)
ntoh函数可以在大端和小端之间进行交换。有些系统也是“中间端”,其中字节被扰乱,而不是按照这种或那种方式排序。
无论如何,如果您关心的只是大端和小端,那么您需要知道的是主机和目标文件的字节顺序是否不同。您将拥有自己的功能,无条件地交换字节顺序,您可以根据是否host_endianess()==objectfile_endianess()
来调用它。
答案 4 :(得分:0)
如果我想一个可以在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);