Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/146.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何将大端结构转换为小端结构?_C++_Struct_Endianness - Fatal编程技术网

C++ 如何将大端结构转换为小端结构?

C++ 如何将大端结构转换为小端结构?,c++,struct,endianness,C++,Struct,Endianness,我有一个在unix机器上创建的二进制文件。这只是一堆一个接一个的记录。记录的定义如下: struct RECORD { UINT32 foo; UINT32 bar; CHAR fooword[11]; CHAR barword[11]; UNIT16 baz; } fstream f; f.open("file.bin", ios::in | ios::binary); RECORD r; f.read((char*)&detail, sizeof(RECOR

我有一个在unix机器上创建的二进制文件。这只是一堆一个接一个的记录。记录的定义如下:

struct RECORD {
  UINT32 foo;
  UINT32 bar;
  CHAR fooword[11];
  CHAR barword[11];
  UNIT16 baz;
}
fstream f;
f.open("file.bin", ios::in | ios::binary);

RECORD r;

f.read((char*)&detail, sizeof(RECORD));

cout << "fooword = " << r.fooword << endl;
inline u_int ByteSwap(u_int in)
{
    u_int out;
    char *indata = (char *)&in;
    char *outdata = (char *)&out;
    outdata[0] = indata[3] ;
    outdata[3] = indata[0] ;

    outdata[1] = indata[2] ;
    outdata[2] = indata[1] ;
    return out;
}

inline u_short ByteSwap(u_short in)
{
    u_short out;
    char *indata = (char *)&in;
    char *outdata = (char *)&out;
    outdata[0] = indata[1] ;
    outdata[1] = indata[0] ;
    return out;
}
struct RECORD {
  UINT32 foo;
  UINT32 bar;
  CHAR fooword[11];
  CHAR barword[11];
  UNIT16 baz;
  void SwapBytes()
  {
    foo = ByteSwap(foo);
    bar = ByteSwap(bar);
    baz = ByteSwap(baz);
  }
}
fstream f;
f.open("file.bin", ios::in | ios::binary);

RECORD r;

f.read((char*)&detail, sizeof(RECORD));
r.SwapBytes();

cout << "fooword = " << r.fooword << endl;
uint32 parse_uint32(char* buffer)
{
  uint32 x;
  // ...
  return x;
}
uint32 value = *reinterpret_cast<uint32*>)(ptr); ptr += 4;
return value;
我正试图弄清楚如何在Windows机器上读取和解释这些数据。我有这样的想法:

struct RECORD {
  UINT32 foo;
  UINT32 bar;
  CHAR fooword[11];
  CHAR barword[11];
  UNIT16 baz;
}
fstream f;
f.open("file.bin", ios::in | ios::binary);

RECORD r;

f.read((char*)&detail, sizeof(RECORD));

cout << "fooword = " << r.fooword << endl;
inline u_int ByteSwap(u_int in)
{
    u_int out;
    char *indata = (char *)&in;
    char *outdata = (char *)&out;
    outdata[0] = indata[3] ;
    outdata[3] = indata[0] ;

    outdata[1] = indata[2] ;
    outdata[2] = indata[1] ;
    return out;
}

inline u_short ByteSwap(u_short in)
{
    u_short out;
    char *indata = (char *)&in;
    char *outdata = (char *)&out;
    outdata[0] = indata[1] ;
    outdata[1] = indata[0] ;
    return out;
}
struct RECORD {
  UINT32 foo;
  UINT32 bar;
  CHAR fooword[11];
  CHAR barword[11];
  UNIT16 baz;
  void SwapBytes()
  {
    foo = ByteSwap(foo);
    bar = ByteSwap(bar);
    baz = ByteSwap(baz);
  }
}
fstream f;
f.open("file.bin", ios::in | ios::binary);

RECORD r;

f.read((char*)&detail, sizeof(RECORD));
r.SwapBytes();

cout << "fooword = " << r.fooword << endl;
uint32 parse_uint32(char* buffer)
{
  uint32 x;
  // ...
  return x;
}
uint32 value = *reinterpret_cast<uint32*>)(ptr); ptr += 4;
return value;
fsf;
f、 打开(“file.bin”,ios::in | ios::binary);
记录r;
f、 读取((字符*)和详细信息,大小(记录));

cout它独立地影响每个成员,而不是整个
struct
。而且,它不会影响数组之类的东西。例如,它只是将
int
s中的字节按相反顺序存储


也就是说,可能有一台机器有着奇怪的末端。我刚才所说的适用于大多数使用过的机器(x86、ARM、PowerPC、SPARC)。

实际上,端性是底层硬件的属性,而不是操作系统的属性

最好的解决方案是在编写数据时转换为标准——谷歌搜索“网络字节顺序”,您应该找到实现这一点的方法


编辑:这里有一个链接:

您必须分别更正多个字节的每个成员的尾数。字符串不需要转换(fooword和barword),因为它们可以被视为字节序列


但是,您必须注意另一个问题:结构中成员的aligmenent。基本上,您必须检查unix和windows代码上的sizeof(RECORD)是否相同。编译器通常提供pragma来定义所需的aligment(例如,#pragma pack)。

以及endian,您需要注意两个平台之间的填充差异。特别是如果您有奇数长度字符数组和16位值,您可能会发现某些元素之间的pad字节数不同

编辑:如果结构是在没有包装的情况下写出来的,那么它应该是相当简单的。类似这样(未经测试)的代码应该可以完成这项工作:

// Functions to swap the endian of 16 and 32 bit values

inline void SwapEndian(UINT16 &val)
{
    val = (val<<8) | (val>>8);
}

inline void SwapEndian(UINT32 &val)
{
    val = (val<<24) | ((val<<8) & 0x00ff0000) |
          ((val>>8) & 0x0000ff00) | (val>>24);
}

<>你还必须考虑这两个编译器之间的对齐差异。允许每个编译器在最适合体系结构的结构中的成员之间插入填充。所以你真的需要知道:

  • UNIX程序如何写入文件
  • 如果它是对象的二进制副本,则表示结构的确切布局
  • 如果它是一个二进制副本,那么源架构的endian属性是什么

这就是为什么大多数程序(我见过(需要是平台无关的))将数据序列化为一个文本流,可以很容易地被标准iostreams读取。

类似的方法应该可以工作:

#include <algorithm>

struct RECORD {
    UINT32 foo;
    UINT32 bar;
    CHAR fooword[11];
    CHAR barword[11];
    UINT16 baz;
}

void ReverseBytes( void *start, int size )
{
    char *beg = start;
    char *end = beg + size;

    std::reverse( beg, end );
}

int main() {
    fstream f;
    f.open( "file.bin", ios::in | ios::binary );

    // for each entry {
    RECORD r;
    f.read( (char *)&r, sizeof( RECORD ) );
    ReverseBytes( r.foo, sizeof( UINT32 ) );
    ReverseBytes( r.bar, sizeof( UINT32 ) );
    ReverseBytes( r.baz, sizeof( UINT16 )
    // }

    return 0;
}
#包括
结构记录{
UINT32-foo;
UINT32巴;
字[11];
字符条码[11];
UINT16-baz;
}
无效反向字节(无效*开始,整数大小)
{
char*beg=start;
char*end=beg+size;
标准::反向(beg,end);
}
int main(){
fsf;
f、 打开(“file.bin”,ios::in | ios::binary);
//对于每个条目{
记录r;
f、 读取((字符*)&r,大小(记录));
反向字节(r.foo,sizeof(UINT32));
反向字节(r.bar,sizeof(UINT32));
反向字节(r.baz,尺寸为UINT16)
// }
返回0;
}

我喜欢为每个需要交换的数据类型实现一个交换字节方法,如下所示:

struct RECORD {
  UINT32 foo;
  UINT32 bar;
  CHAR fooword[11];
  CHAR barword[11];
  UNIT16 baz;
}
fstream f;
f.open("file.bin", ios::in | ios::binary);

RECORD r;

f.read((char*)&detail, sizeof(RECORD));

cout << "fooword = " << r.fooword << endl;
inline u_int ByteSwap(u_int in)
{
    u_int out;
    char *indata = (char *)&in;
    char *outdata = (char *)&out;
    outdata[0] = indata[3] ;
    outdata[3] = indata[0] ;

    outdata[1] = indata[2] ;
    outdata[2] = indata[1] ;
    return out;
}

inline u_short ByteSwap(u_short in)
{
    u_short out;
    char *indata = (char *)&in;
    char *outdata = (char *)&out;
    outdata[0] = indata[1] ;
    outdata[1] = indata[0] ;
    return out;
}
struct RECORD {
  UINT32 foo;
  UINT32 bar;
  CHAR fooword[11];
  CHAR barword[11];
  UNIT16 baz;
  void SwapBytes()
  {
    foo = ByteSwap(foo);
    bar = ByteSwap(bar);
    baz = ByteSwap(baz);
  }
}
fstream f;
f.open("file.bin", ios::in | ios::binary);

RECORD r;

f.read((char*)&detail, sizeof(RECORD));
r.SwapBytes();

cout << "fooword = " << r.fooword << endl;
uint32 parse_uint32(char* buffer)
{
  uint32 x;
  // ...
  return x;
}
uint32 value = *reinterpret_cast<uint32*>)(ptr); ptr += 4;
return value;
然后我向需要交换的结构中添加一个函数,如下所示:

struct RECORD {
  UINT32 foo;
  UINT32 bar;
  CHAR fooword[11];
  CHAR barword[11];
  UNIT16 baz;
}
fstream f;
f.open("file.bin", ios::in | ios::binary);

RECORD r;

f.read((char*)&detail, sizeof(RECORD));

cout << "fooword = " << r.fooword << endl;
inline u_int ByteSwap(u_int in)
{
    u_int out;
    char *indata = (char *)&in;
    char *outdata = (char *)&out;
    outdata[0] = indata[3] ;
    outdata[3] = indata[0] ;

    outdata[1] = indata[2] ;
    outdata[2] = indata[1] ;
    return out;
}

inline u_short ByteSwap(u_short in)
{
    u_short out;
    char *indata = (char *)&in;
    char *outdata = (char *)&out;
    outdata[0] = indata[1] ;
    outdata[1] = indata[0] ;
    return out;
}
struct RECORD {
  UINT32 foo;
  UINT32 bar;
  CHAR fooword[11];
  CHAR barword[11];
  UNIT16 baz;
  void SwapBytes()
  {
    foo = ByteSwap(foo);
    bar = ByteSwap(bar);
    baz = ByteSwap(baz);
  }
}
fstream f;
f.open("file.bin", ios::in | ios::binary);

RECORD r;

f.read((char*)&detail, sizeof(RECORD));
r.SwapBytes();

cout << "fooword = " << r.fooword << endl;
uint32 parse_uint32(char* buffer)
{
  uint32 x;
  // ...
  return x;
}
uint32 value = *reinterpret_cast<uint32*>)(ptr); ptr += 4;
return value;
然后,您可以修改读取(或写入)结构的代码,如下所示:

struct RECORD {
  UINT32 foo;
  UINT32 bar;
  CHAR fooword[11];
  CHAR barword[11];
  UNIT16 baz;
}
fstream f;
f.open("file.bin", ios::in | ios::binary);

RECORD r;

f.read((char*)&detail, sizeof(RECORD));

cout << "fooword = " << r.fooword << endl;
inline u_int ByteSwap(u_int in)
{
    u_int out;
    char *indata = (char *)&in;
    char *outdata = (char *)&out;
    outdata[0] = indata[3] ;
    outdata[3] = indata[0] ;

    outdata[1] = indata[2] ;
    outdata[2] = indata[1] ;
    return out;
}

inline u_short ByteSwap(u_short in)
{
    u_short out;
    char *indata = (char *)&in;
    char *outdata = (char *)&out;
    outdata[0] = indata[1] ;
    outdata[1] = indata[0] ;
    return out;
}
struct RECORD {
  UINT32 foo;
  UINT32 bar;
  CHAR fooword[11];
  CHAR barword[11];
  UNIT16 baz;
  void SwapBytes()
  {
    foo = ByteSwap(foo);
    bar = ByteSwap(bar);
    baz = ByteSwap(baz);
  }
}
fstream f;
f.open("file.bin", ios::in | ios::binary);

RECORD r;

f.read((char*)&detail, sizeof(RECORD));
r.SwapBytes();

cout << "fooword = " << r.fooword << endl;
uint32 parse_uint32(char* buffer)
{
  uint32 x;
  // ...
  return x;
}
uint32 value = *reinterpret_cast<uint32*>)(ptr); ptr += 4;
return value;
fsf;
f、 打开(“file.bin”,ios::in | ios::binary);
记录r;
f、 读取((字符*)和详细信息,大小(记录));
r、 交换字节();

cout不要直接从文件读入struct!打包可能会有所不同,你必须摆弄pragma pack或类似的编译器特定结构。太不可靠了。很多程序员都能侥幸逃脱,因为他们的代码没有在大量的体系结构和系统中编译,但这并不意味着这是可以做到的

一种很好的替代方法是将头读入缓冲区,然后从3解析,以避免原子操作中的I/O开销,例如读取无符号32位整数

char buffer[32];
char* temp = buffer;  

f.read(buffer, 32);  

RECORD rec;
rec.foo = parse_uint32(temp); temp += 4;
rec.bar = parse_uint32(temp); temp += 4;
memcpy(&rec.fooword, temp, 11); temp += 11;
memcpy(%red.barword, temp, 11); temp += 11;
rec.baz = parse_uint16(temp); temp += 2;
parse_uint32的声明如下所示:

struct RECORD {
  UINT32 foo;
  UINT32 bar;
  CHAR fooword[11];
  CHAR barword[11];
  UNIT16 baz;
}
fstream f;
f.open("file.bin", ios::in | ios::binary);

RECORD r;

f.read((char*)&detail, sizeof(RECORD));

cout << "fooword = " << r.fooword << endl;
inline u_int ByteSwap(u_int in)
{
    u_int out;
    char *indata = (char *)&in;
    char *outdata = (char *)&out;
    outdata[0] = indata[3] ;
    outdata[3] = indata[0] ;

    outdata[1] = indata[2] ;
    outdata[2] = indata[1] ;
    return out;
}

inline u_short ByteSwap(u_short in)
{
    u_short out;
    char *indata = (char *)&in;
    char *outdata = (char *)&out;
    outdata[0] = indata[1] ;
    outdata[1] = indata[0] ;
    return out;
}
struct RECORD {
  UINT32 foo;
  UINT32 bar;
  CHAR fooword[11];
  CHAR barword[11];
  UNIT16 baz;
  void SwapBytes()
  {
    foo = ByteSwap(foo);
    bar = ByteSwap(bar);
    baz = ByteSwap(baz);
  }
}
fstream f;
f.open("file.bin", ios::in | ios::binary);

RECORD r;

f.read((char*)&detail, sizeof(RECORD));
r.SwapBytes();

cout << "fooword = " << r.fooword << endl;
uint32 parse_uint32(char* buffer)
{
  uint32 x;
  // ...
  return x;
}
uint32 value = *reinterpret_cast<uint32*>)(ptr); ptr += 4;
return value;
这是一个非常简单的抽象,在实践中更新指针也不需要额外的成本:

uint32 parse_uint32(char*& buffer)
{
  uint32 x;
  // ...
  buffer += 4;
  return x;
}
后一种形式允许更干净的代码来解析缓冲区;当您解析输入时,指针会自动更新

同样,memcpy也可以有一个助手,比如:

void parse_copy(void* dest, char*& buffer, size_t size)
{
  memcpy(dest, buffer, size);
  buffer += size;
}
这种安排的美妙之处在于,您可以使用名称空间“little_endian”和“big_endian”,然后您可以在代码中这样做:

using little_endian;
// do your parsing for little_endian input stream here..
对于相同的代码,很容易切换尾数,但很少需要特性。文件格式通常都有固定的尾数

不要使用虚拟方法将其抽象到类中;这只会增加开销,但如果愿意,可以:

little_endian_reader reader(data, size);
uint32 x = reader.read_uint32();
uint32 y = reader.read_uint32();
reader对象显然只是指针周围的一个薄包装器。size参数将用于错误检查(如果有的话)。对于接口本身来说,这并不是必须的

注意这里的endian选择是如何在编译时完成的(因为我们创建了一个小的_endian _reader对象),所以我们调用虚拟方法开销没有什么特别好的理由,所以我不会使用这种方法。;-)

在这个阶段,没有真正的理由保持“fileformat结构”不变,您可以根据自己的喜好组织数据,而不必将其读入任何特定的结构中;毕竟,这只是数据。当你阅读像图像这样的文件时,你实际上不需要标题。。您应该拥有与所有文件类型相同的图像容器,因此读取特定格式的代码应该只读取文件、解释和重新格式化数据并存储有效负载。=)

我是说,这看起来复杂吗

uint32 xsize = buffer.read<uint32>();
uint32 ysize = buffer.read<uint32>();
float aspect = buffer.read<float>();    
uint32 xsize=buffer.read();
uint32 ysize=buffer.read();
float aspect=buffer.read();
代码可以看起来很好,而且开销非常低!如果endi