在c语言中对结构体进行字节交换的泛型函数



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

下面是一个例子:

#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. 重复此过程,直到最后一个成员被字节交换。

这样,一个函数就可以很好地交换任何结构体的字节,而不考虑其定义。

是否有可用的库可以这样做?

一个例子:我想实现一些东西,比如

typedef struct {
int num1;
int num2;
}TestStruct1;
typedef struct {
int num1;
int num2;
int num3;
}TestStruct2;
typedef struct {
int num1;
int num2;
int num3;
int num4;
}TestStruct3;
void bswap_struct(void* any_struct); /* one single function to byte swap any struct in the world */
int main(void) {
TestStruct1 tstruct1;
TestStruct2 tstruct2;
TestStruct3 tstruct3;
/* Code to initialize tstruct1, tstruct2, tstruct3 */
tstruct1 = { 0x1234, 0x5678 };
tstruct2 = { 0x2345, 0x6789, 0x7890 };
tstruct3 = { 0x1234, 0x5678, 0x3456, 0x8901 };
/* byte swap all structs */
bswap_struct(&tstruct1);
bswap_struct(&tstruct2);
bswap_struct(&tstruct3);
return 0;
}

如果存在一种方法可以在不知道结构体实际定义的情况下进行字节交换,

不,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
)
}

一般我会这样做:

#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,0x44, 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))
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, i128);
print(&str.i128, sizeof(str.i128));
print(&str.num64_1, sizeof(str.num64_1));
BSWAPMEMBER(&str, num64_1);
print(&str.num64_1, sizeof(str.num64_1));
}

https://godbolt.org/z/4xEMMcrcd

它适用于任何大小的成员(例如数组)https://godbolt.org/z/cn9G7jWav

最新更新