字节交换和C++/C 我在Cop.Lang.c++上做了一个帖子,得到了这个

字节交换和C++/C 我在Cop.Lang.c++上做了一个帖子,得到了这个,c++,c,binaryfiles,C++,C,Binaryfiles,但这仍然不是答案 我对二进制读取操作有点困惑 我正在尝试使用流函数读取二进制文件。这是一个商业程序(ANSYS)的结果文件,我知道该文件的结构,至少是从手册中知道的 该文件是以记录的形式构造的,程序是用fortran编写的。所以结构就像 记录长度(整数) 伪整数 数据(可以是整数,也可以是双精度) 伪整数 第一条记录是一个100整数块,其中对应于上述表示中的数据 如果我开始读取文件并读取第一个值,即记录长度(整数),我必须交换字节以获得正确的值100 我不明白为什么我必须交换字节,因为这个文件是

但这仍然不是答案

我对二进制读取操作有点困惑

我正在尝试使用流函数读取二进制文件。这是一个商业程序(ANSYS)的结果文件,我知道该文件的结构,至少是从手册中知道的

该文件是以记录的形式构造的,程序是用fortran编写的。所以结构就像

记录长度(整数) 伪整数 数据(可以是整数,也可以是双精度) 伪整数

第一条记录是一个100整数块,其中对应于上述表示中的数据

如果我开始读取文件并读取第一个值,即记录长度(整数),我必须交换字节以获得正确的值100

我不明白为什么我必须交换字节,因为这个文件是在同一台机器上生成的,它们应该使用相同的系统特定例程,所以这不应该是一个问题,但情况似乎并非如此。还有别的事。我无法理解这一点。软件会被迫交换字节吗?我很难理解原因

如有任何意见,我们将不胜感激

下面是一个简单的测试用例

int main () {
  ifstream myfile;
  char intBuffer[4];
  myfile.open ("truss.rst", ios::binary);
  myfile.read(intBuffer, sizeof(int));
  //cout << *((int*)intBuffer) << endl;
  // if I do not use this portion-
  // I do not get what I want
  char *cptr, tmp;
  tmp = intBuffer[0];
  intBuffer[0] = intBuffer[3];
  intBuffer[3] = tmp;
  tmp = intBuffer[1];
  intBuffer[1] = intBuffer[2];
  intBuffer[2] = tmp;
  // -----------------------------
  cout << *((int*)intBuffer) << endl;

  myfile.close();
  return 0;
}
int main(){
ifstreammyfile;
char intBuffer[4];
myfile.open(“truss.rst”,ios::binary);
read(intBuffer,sizeof(int));

//cout也许软件执行这种“奇怪”操作是为了支持小/大端体系结构(字节顺序不同)

结论:

  • 在两台不同的机器(little/big-endian)上,如果在文件中插入二进制信息,使用相同的输入,文件可能会不同

也许软件执行这种“奇怪”操作是为了支持小/大端体系结构(字节顺序不同)

结论:

  • 在两台不同的机器(little/big-endian)上,如果在文件中插入二进制信息,使用相同的输入,文件可能会不同

一些文件格式要求字节顺序为单一方式,通常为大端,因为这是网络顺序,所以在little-endian x86s上,这些文件在写入时的ints字节交换,在读取时的ints字节交换

一些文件格式要求字节顺序为单一方式,通常为大端,因为这是网络顺序,所以在little-en上dian x86这些文件在写入时交换ints字节,在读取时交换回ints字节

无论是何种格式,显然在不同的机器上都是一致的(如果无法在另一台机器上打开文件,那就有点好笑了)


因此,字节顺序和数据类型大小都必须在格式中定义,并且当您想要读取这种格式时,您需要处理这些字节顺序和数据类型大小。

无论是什么格式,它显然在不同的机器上都是一致的(如果您无法在另一台机器上打开文件,这将是一件有趣的事情)


因此,字节顺序和数据类型大小都必须在格式中定义,并且当您想要读取这种格式时,您需要使用这些字节顺序和数据类型大小。

这不仅仅取决于您所使用的机器。如果Fortran基础结构以大端而不是小端写整数,您必须不管操作系统是什么,都要处理这个问题


我建议您使用
ntohl()
ntohs()
函数,它们比您的交换例程更清晰。

这不仅仅取决于您正在使用的机器。如果Fortran基础结构以大端而不是小端写整数,那么无论操作系统是什么,您都必须处理这些问题


我建议您使用
ntohl()
ntohs()
函数,它们比您的交换例程更清晰。

这是。英特尔CPU使用小端。网络字节顺序/SPARC/Motorola使用big-endian。许多传统的便携式应用程序将文件保存在big-endian中以实现互操作性。

这是一个。Intel CPU使用little-endian。“网络字节顺序”/SPARC/Motorola使用big-endian。许多传统的便携式应用程序将文件保存在big-endian中以实现互操作性。

有一些众所周知的时候,您自愿强制执行一个字节顺序:当数据打算在开始时未知端号的机器之间交换时,例如通过网络。这就是为什么有C-primiti像
ntohl
htonl
:如果网络端和机器端相同,那么它们什么都不做,否则它们交换字节。如果文件应该在机器之间交换,那么这里可能会涉及类似的内容

但真正的问题是:在数据块中是否也存在相同的字节交换。如果没有,则确实存在一些奇怪的情况,0可能只是填充,而不是格式的所有部分。如果字节交换也发生在数据块中,则可能是故意的

最可移植的解决方案当然是逐字节读取文件并手工组装数据,因此您可能能够处理大于uint32\t的整数

当读取双倍时,也要准备好遇到一些麻烦,因为字节顺序也可能是交换的,而且它们不容易手工组装

下面的代码可以作为任何类型的模板,您可以更改其endianness,包括double

#include <stdio.h>
#include <arpa/inet.h>
#include <stdint.h>

template <class builtin>
builtin ntoh(const builtin input) {
    if ((int)ntohs(1) != 1){
        union {
            char buffer[sizeof(builtin)];
            builtin data;
        } in, out;
        in.data = input;
        for (int i = 0 ; i < sizeof(builtin); i++){
            out.buffer[i] = in.buffer[sizeof(builtin) - i - 1];
        }
        return out.data;
    }
    return input;
}

main(){
    printf ("78563412 expected, got: output= %x\n", ntoh<uint32_t>(0x12345678));
}
#包括

#包含以获得本机类型的更好性能。

有一些众所周知的时候,您自愿强制执行一个字节顺序:当数据打算在一开始端号未知的机器之间交换时,例如通过网络。这就是为什么会有C原语,如
ntohl
htonl
:如果网络eNDianes与machine endianness相同,它们什么都不做,否则它们会交换字节。如果文件应该交换,那么这里可能会涉及类似的内容
void byteswap( unsigned char & byte1, unsigned char & byte2 )
{
   byte1 ^= byte2;
   byte2 ^= byte1;
   byte1 ^= byte2;
}
uint32_t count = 0;
myfile.open ("truss.rst", ios::binary);
myfile.read(reinterpret_cast<char*>(&count), sizeof(uint32_t)); 
   // ideally validate that the read succeeded
count = ntohl( count );