C-大端结构与小端结构互转换

时间:2018-12-26 04:24:48

标签: c gcc optimization struct

我有两个具有相同数据成员的结构。 (一个是 big_endian 结构,另一个是 little_endian ),现在我必须与它们进行相互转换。但是当我编写代码时,我发现有很多重复的代码,几乎没有变化。如果没有重复的代码,如何更改这些代码以使其更美观? (重复的代码表示这些代码可能相似,例如mode == 1mode == 2,它们的分配位置不同。它看起来不雅,但可以使用。)

这是我的代码:

#pragma scalar_storage_order big-endian

typedef struct {   
    int a1;    
    short a2;    
    char a3;    
    int a4;    
} test_B;

#pragma scalar_storage_order default

typedef struct {
    int a1;    
    short a2;    
    char a3;    
    int a4;    
} test_L;


void interconvert(test_L *little, test_B *big, int mode) {
    // if mode == 1 , convert little to big    
    // if mode == 2 , convert big to little    
    // it may be difficult and redundant when the struct has lots of data member!    
    if(mode == 1) {
        big->a1 = little->a1;
        big->a2 = little->a2;
        big->a3 = little->a3;
        big->a4 = little->a4;
    }
    else if(mode == 2) {
        little->a1 = big->a1;
        little->a2 = big->a2;
        little->a3 = big->a3;
        little->a4 = big->a4;
    }
    else return;
}

注意:由于#pragma scalar_storage_order

,以上代码必须在 gcc-7或更高版本上运行

1 个答案:

答案 0 :(得分:-1)

发布了一个答案,建议使用memcpy解决此问题,但该答案已删除。实际上,如果使用正确,答案是正确的,我想解释原因。

OP指出的#pragma是中央的,

  

注意:由于#pragma scalar_storage_order

,以上代码必须在gcc-7或更高版本上运行

OP中的结构:

#pragma scalar_storage_order big-endian
typedef struct {   
    int a1;    
    short a2;    
    char a3;    
    int a4;    
} test_B;

表示指令“ test_B.a2 = 256”在属于a2成员的两个连续字节中分别写入1和0。这是big-endian。类似的指令“ test_L.a2 = 256”将替代字节0和1(小尾数)。

以下memcpy:

memcpy(&test_L, &test_B, sizeof test_L)

将使test_L.a2的字节等于1和0,因为这是test_B.a2的RAM内容。但是现在,在小字节序模式下读取test_L.a2,这两个字节表示1。我们写入256,然后回读1。这正是所需的转换。

要正确使用此机制,只需在一个结构中编写memcpy()并在另一个结构中逐个读取另一个结构就足够了。大字节序变成小字节序,反之亦然。当然,如果要详细说明数据并对其进行计算,则重要的是要知道数据的字节序;如果它与默认模式匹配,则在计算之前不必执行任何转换,但必须稍后应用转换。相反,如果传入的数据与处理器的“默认字节序”不匹配,则必须先对其进行转换。


编辑 在下面的OP评论之后,我进行了更多调查。我看了一下这个https://gcc.gnu.org/onlinedocs/gcc/Structure-Layout-Pragmas.html

嗯,有三种#pragma可以选择字节布局: big-endian little-endian default 。前两个等于最后一个:如果目标计算机为little-endian,则默认为little-endian;否则为false。如果是big-endian,则默认为big-endian。这不只是逻辑上的。

因此,在big-endian和default之间进行memcpy()不会对big-endian机器产生任何影响。这也是合乎逻辑的。好的,更好的是,我要强调的是memcpy()本身绝对不会做任何事情:它只会将数据从以某种方式处理的ram区域移到以另一种方式处理的另一个区域。仅当完成普通成员访问后,才会对两个不同的区域进行不同的处理:这里是播放 #pragma scalar_storage_order 的过程。正如我之前写的,了解哪些字节序的数据进入程序很重要。例如,如果它们来自TCP网络,则我们知道这是big-endian。更一般而言,如果它是从“程序”外部获取并遵守协议,则我们应该知道字节序的含义。

要从字节序转换为另一字节序,应使用 little big NOT 默认值,因为 default < / em>肯定等于前两个之一。


仍然进行其他修改

受评论的刺激,以及使用在线编译器的Jamesdlin的启发,我也尝试这样做。在此网址http://tpcg.io/lLe5EW 有一个示例说明了将一个成员分配给一个结构,将memcpy分配给另一个结构,并读完后,进行了字节序转换。就是这样。