c - c 位域的平台独立存储

标签 c bit-fields

我使用 C 位域在内存中存储数据。对于存档使用,这些数据必须写入文件(然后与来自另一台机器的数据组合)。将位域直接保存到文件似乎不是一个好主意,因为数据的排列是特定于实现的。

为此,我写了一些方法来“序列化”这些位域,以统一格式保存它们:

/* uint16 is a unsigned int with size 16 */

typedef struct {
    uint16 a : 1;
    /* ... just examples ... */
    uint16 z : 13;
} data;

void save_data(FILE* fp, data d) {
    uint16 tmp;
    tmp = d.a;
    fwrite(&tmp,sizeof(uint16),1,fp);
    /* ... */
    tmp = d.z;
    fwrite(&tmp,sizeof(uint16),1,fp);
}

虽然这很完美,但似乎不太适合扩展,因为在 data 中添加更多成员需要将数据也添加到保存例程中。

有什么技巧可以在更改位域数据时无需适配例程/宏自动将位域数据转换为统一格式?

最佳答案

这是一种方法。我不能推荐它,但它在那里并且它有点有效,所以为什么不看看它。这种化身仍然依赖于平台,但您可以轻松切换到独立于平台、可能是人类可读的格式。为简洁起见,省略了错误处理。

// uglymacro.h
#if defined(DEFINE_STRUCT)

#define BEGINSTRUCT(struct_tag)     typedef struct struct_tag {
#define ENDSTRUCT(struct_typedef)   } struct_typedef;
#define BITFIELD(name,type,bit)     type name : bit;
#define FIELD(name,type)            type name;
#define ARRAYFIELD(name,type,size)  type name[size];

#elif defined(DEFINE_SAVE)

#define BEGINSTRUCT(struct_tag)     void save_##struct_tag(FILE* fp, \
                                                           struct struct_tag* p_a) {
#define ENDSTRUCT(struct_typedef)   }
#define BITFIELD(name,type,bit)     { type tmp; tmp = p_a->name; \
                                      fwrite (&tmp, sizeof(type), 1, fp); }
#define FIELD(name,type)            { fwrite (&p_a->name, sizeof(p_a->name), 1, fp); }
#define ARRAYFIELD(name,type,size)  { fwrite (p_a->name, sizeof(p_a->name[0]), size, fp); }

#elif defined(DEFINE_READ)

#define BEGINSTRUCT(struct_tag)     void read_##struct_tag(FILE* fp, \
                                                           struct struct_tag* p_a) {
#define ENDSTRUCT(struct_typedef)   }
#define BITFIELD(name,type,bit)     { type tmp; fread (&tmp, sizeof(type), 1, fp); \
                                      p_a->name = tmp; }
#define FIELD(name,type)            { fread (&p_a->name, sizeof(p_a->name), 1, fp); }
#define ARRAYFIELD(name,type,size)  { fread (p_a->name, sizeof(p_a->name[0]), size, fp); }

#else
#error "Must define either DEFINE_STRUCT or DEFINE_SAVE or DEFINE_READ"
#endif

#undef DEFINE_STRUCT
#undef DEFINE_READ
#undef DEFINE_WRITE
#undef BEGINSTRUCT
#undef ENDSTRUCT
#undef FIELD
#undef BITFIELD
#undef ARRAYFIELD

您的结构定义如下所示:

// mystruct_def.h
BEGINSTRUCT(mystruct)
BITFIELD(a,int,1)
FIELD(b,int)
ARRAYFIELD(c,int,10)
ENDSTRUCT(mystruct)

你可以这样使用它:

// in mystruct.h file
#define DEFINE_STRUCT
#include "uglymacro.h"
#include "mystruct_def.h"

// in mystruct.c file
#include "mystruct.h"
#define DEFINE_READ
#include "mystruct_def.h"
#define DEFINE_WRITE
#include "mystruct_def.h"

坦率地说,按照现代标准,这种方法很丑陋。我在大约 20 年前使用过类似的东西,当时它很丑。

另一种选择是使用更人性化的代码生成工具而不是 C 预处理器。

关于c - c 位域的平台独立存储,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17831578/

相关文章:

无法在函数调用中更改动态分配的数组值

c++ - std::vector<bool> 上的运算符 |=

c - 如何确定/测量具有位字段的结构的大小?

c - 分配给结构成员的值不正确

c++ - 在 ab 中调用函数(C/C++)的官方方法是什么?在 Linux 上每 1/100 秒?

无法使用 write 系统调用将整个文件复制到另一个文件

c - gdb 不接受用户输入

c - javacc C 语法和 C "Bit fields";解析异常

c - 使用位字段在新的二进制文件中写入自定义的 n 位数据

计算长字符串中的字符数