C++ 识别endian相关问题

C++ 识别endian相关问题,c++,c,endianness,C++,C,Endianness,我最近了解了endianness,但仍然难以确定问题区域 下面是一段代码,它使用从二进制文件(Dxt纹理)加载的数据。我不确定endianness是否会在这种情况下导致问题,例如宽度、高度和十六进制比较。我需要改变什么?为什么 DxtHeader* header = (DxtHeader*)data; width = header->width; height = header->height; uint pixelFormat = header->pixelFormat.f

我最近了解了endianness,但仍然难以确定问题区域

下面是一段代码,它使用从二进制文件(Dxt纹理)加载的数据。我不确定endianness是否会在这种情况下导致问题,例如宽度、高度和十六进制比较。我需要改变什么?为什么

DxtHeader* header = (DxtHeader*)data;
width = header->width;
height = header->height;

uint pixelFormat = header->pixelFormat.fourCC;
if (pixelFormat == 0x31545844){
    ...
} else if (pixelFormat == 0x33545844){
    ...
} else if (pixelFormat == 0x35545844){
    ...
}

一般来说,只有当您的数据通过某个物理接口(例如,通过网络或文件)传输时,端性才起作用,而该物理接口可能来自具有不同本机端性的平台。如果您试图用指针强制转换做“聪明”的事情,例如
inta=0xABCD;字符b=*(字符*)&a

从您的示例中不清楚原始数据来自何处,但我假设它是从文件或其他地方读取的。实际上,处理endianness转换的最佳位置是尽可能靠近接口,因此在您的例子中,读取文件并填充结构的例程。通常,这可以用预处理器αIFIFS来解决,例如C(我知道这是C++问题,但我相信你能找到一个适当的等价物):

#ifdef(LITTLE_ENDIAN)
#将文件定义为本地文件16(x)((x)和0xFF)>8))
#否则
#将文件定义为本地文件16(x)(x)
#恩迪夫
等等


如果将转换隔离到接口例程,那么代码的其余部分将成为endian不可知的。

可能最好首先保存适合目标平台的数据。也就是说,当您创建数据文件时,endian将交换所有字段


撇开这一点不谈,我认为您的DXT加载器应该自动处理这一问题,因为DXT通常将构建在Windows机器上,这些机器现在都是little endian。

它被标记为C,所以C代码应该非常好。(呃,我不喜欢人们在一个问题中将C/C++混为一谈)我们不知道这是否发生在他的代码中——这取决于他正在加载的文件格式,以及他打算支持的endianess
pixelFormat==0x31545844
可能在一个平台上工作,而在另一个平台上它必须是
pixelFormat==0x44585431
。@否:是的,你是对的。据此编辑了我的答案。然而,解决方案不是修改所有常量,因为这很快就会成为一场噩梦。这取决于DXTexture头的API定义。如果像素格式被记录为uint,那么常量应定义为uint,这意味着它们是相同的,而不管端点如何。如果数据来自另一台机器的二进制格式,则可能存在endianness问题,但正确的转换位置是反序列化。顺便说一下,在本例中,像素格式常量是向后的。4cc代码通常是由4个ASCII字符组成的序列。如果反转代码段中的常量,则分别得到DXT1、DXT3和DXT5。因此,假设这是一台英特尔机器,我会说这些文件是以网络字节顺序存储的。作为一种风格,您应该定义像素格式的值,这样代码就更易于维护/可读。另外,使用
switch
语句,而不是大量的
if
/
else
块。这是一个很好的总结,可以解释endianness:我知道,我只是想用尽可能少的代码来展示它。如果文本文件是UTF-16或UTF-32文本文件,你需要担心。如果是ASCII或UTF-8,则不需要。@nategoose这些文件不是文本文件。它们的像素数据是用字节编码的,而不是用字母编码的。
#ifdef (LITTLE_ENDIAN)
#define FILE_TO_NATIVE_16(x)  ((((x) & 0xFF) << 8) | ((x) >> 8))
#else
#define FILE_TO_NATIVE_16(x)  (x)
#endif