在 C 中字节交换结构的通用函数

问题描述 投票:0回答:2

我知道字节交换结构的一种方法是分别字节交换每个单独的成员变量。

下面是一个例子。

   #include<stdio.h>
   #include<byteswap.h>

   #define Uint16 unsigned short int
   #define Uint32 unsigned int
   
   typedef struct {
      Uint16 num16_1;
      Uint16 num16_2;
      Uint32 num32_1;
      Uint16 num16_3;
      char   ch_1;
      char   ch_2;
      Uint32 num32_2;
   }TestStruct;

   void InitTestStruct(TestStruct* buffer) {

      buffer->num16_1 = (Uint16) 0x1234;
      buffer->num16_2 = (Uint16) 0x5678;
      buffer->num32_1 = (Uint32) 0x56781234;
      buffer->num16_3 = (Uint16) 0x4321;

      buffer->ch_1 = 'a';
      buffer->ch_2 = 'b';

      buffer->num32_2 = (Uint32) 0x12345678;
   }

   void SwapTestStruct(TestStruct* buffer) {

      buffer->num16_1 = bswap_16(buffer->num16_1);
      buffer->num16_2 = bswap_16(buffer->num16_2 );
      buffer->num32_1 = bswap_32(buffer->num32_1 );
      buffer->num16_3 = bswap_16(buffer->num16_3 );

      //ch_1; /* chars do not need byte swapping */
      //ch_2; /* chars do not need byte swapping */

      buffer->num32_2 = bswap_32(buffer->num32_1);
   }
   
   void PrintTestStruct(TestStruct buffer) {

      printf("********************************************\n");
      printf("buffer.num16_1 - [%04x]\n", buffer.num16_1);
      printf("buffer.num16_2 - [%04x]\n", buffer.num16_2);
      printf("buffer.num32_1 - [%04x]\n", buffer.num32_1);
      printf("buffer.num16_3 - [%04x]\n", buffer.num16_3);
      printf("buffer.ch_1    - [%c]\n",   buffer.ch_1);
      printf("buffer.ch_2    - [%c]\n",   buffer.ch_2);
      printf("buffer.num32_2 - [%04x]\n", buffer.num32_2);
      printf("********************************************\n");
}

   int main(void) {

      TestStruct tstruct;

      InitTestStruct(&tstruct);   /* Initialize the TestStruct */

      PrintTestStruct(tstruct);
      
      SwapTestStruct(&tstruct);   /* Byte swap the TestStruct */

      PrintTestStruct(tstruct);

      return 0;
   }

我正在尝试查看是否有一种方法可以在不知道实际结构定义的情况下字节交换结构。

  1. 就像,要获得结构的第一个成员变量的偏移量,字节交换它。
  2. 然后获取第二个成员的偏移量并进行字节交换。
  3. 重复这个过程,直到最后一个成员被字节交换。

这样,无论定义如何,单个函数就足以对任何结构进行字节交换。

是否有任何可用的库可以执行此操作?

c struct endianness
2个回答
2
投票

如果有一种方法可以在不知道实际结构定义的情况下字节交换结构。

不,C 编程语言没有反射。你,程序员,必须告诉程序使用了哪些类型。


使用一些 _Generic 和预处理器 FOREACH 宏,您可以只列出结构的成员名称,如下所示。我不认为我会编写这样的代码——我很可能会保留您提供的代码,因为它更具可读性,更容易调试和理解,并允许 IDE“重命名”功能正常工作。

#include <stdint.h>
#include <byteswap.h>

#define FOREACH_1(f,c,a)     f(c,a)
#define FOREACH_2(f,c,a,...) f(c,a) FOREACH_1(f,c,__VA_ARGS__)
#define FOREACH_3(f,c,a,...) f(c,a) FOREACH_2(f,c,__VA_ARGS__)
#define FOREACH_4(f,c,a,...) f(c,a) FOREACH_3(f,c,__VA_ARGS__)
#define FOREACH_5(f,c,a,...) f(c,a) FOREACH_4(f,c,__VA_ARGS__)
#define FOREACH_6(f,c,a,...) f(c,a) FOREACH_5(f,c,__VA_ARGS__)
#define FOREACH_7(f,c,a,...) f(c,a) FOREACH_6(f,c,__VA_ARGS__)
#define FOREACH_8(f,c,a,...) f(c,a) FOREACH_7(f,c,__VA_ARGS__)
#define FOREACH_9(f,c,a,...) f(c,a) FOREACH_8(f,c,__VA_ARGS__)
#define FOREACH_N(_9,_8,_7,_6,_5,_4,_3,_2,_1,N,...)  FOREACH##N
#define FOREACH(f,ctx,...)  FOREACH_N(__VA_ARGS__,_9,_8,_7,_6,_5,_4,_3,_2,_1)(f,ctx,__VA_ARGS__)

#define BSWAP_STRUCT_ONE(var, memb)  _Generic((var->memb), \
    char: 0, \
    uint8_t: 0, \
    uint16_t: (var->memb = bswap_16(var->memb)), \
    uint32_t: (var->memb = bswap_32(var->memb)));
#define BSWAP_STRUCT(var, ...)  FOREACH(BSWAP_STRUCT_ONE, var, __VA_ARGS__)

typedef struct {
    uint16_t num16_1;
    uint16_t num16_2;
    uint16_t num32_1;
    uint16_t num16_3;
    char   ch_1;
    char   ch_2;
    uint32_t num32_2;
} TestStruct;

void SwapTestStruct(TestStruct* buffer) {
    BSWAP_STRUCT(
        buffer,
        num16_1,
        num16_2,
        num32_1,
        num16_3,
        ch_1,
        ch_2,
        num32_2
    )
}

0
投票

通用我会做这样的事情:

#define GETSIZE(type, memb) sizeof((type){0,}.memb)
#define BSWAPMEMBER(ptr, type, memb) bswap(ptr, offsetof(type, memb), GETSIZE(type, memb))

typedef struct {
    uint16_t num16_1;
    uint16_t num16_2;
    uint64_t num64_1;
    char   ch_1;
    char   ch_2;
    __int128 i128;
} TestStruct;

void *bswap(void *ptr, const size_t offset, const size_t size)
{
    unsigned char *start = ptr;
    unsigned char *end;

    if(ptr && size)
    {
        start += offset;
        end = start + size - 1;
        while(start < end)
        {
            unsigned char temp = *start;
            *start++ = *end;
            *end-- = temp;
        }
    }
    return ptr;
}

void print(const void *ptr, size_t size)
{
    const unsigned char *ucp = ptr;
    for(size_t index = 0; index < size; index ++)
        printf("0x%hhX ", *ucp++);
    printf("\n");
}

int main(void)
{
    TestStruct str = {.num64_1 = 0x1122334455667788ULL};
    unsigned char testarr[] = {0x00,0x11,0x22,0x33,0x55,0x66, 0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff};
    memcpy(&str.i128, testarr, sizeof(testarr));

    print(&str.i128, sizeof(str.i128));
    BSWAPMEMBER(&str, TestStruct, i128);
    print(&str.i128, sizeof(str.i128));

    print(&str.num64_1, sizeof(str.num64_1));
    BSWAPMEMBER(&str, TestStruct, num64_1);
    print(&str.num64_1, sizeof(str.num64_1));
}

https://godbolt.org/z/aqa4qrY61

或者如果你使用 gcc 或真正新的 C 标准

#define BSWAPMEMBER(ptr, memb) bswap(ptr, offsetof(typeof(*(ptr)), memb), GETSIZE(typeof(*(ptr)), memb))
© www.soinside.com 2019 - 2024. All rights reserved.