0%

结构体偏移

结构体偏移

项目通过定义union联合体使用同一块内存, 在代码运行的不同阶段访问具体的成员。针对一些希望跨阶段存在的数据在不同的结构中保持了一份相同的成员,保证在不同的阶段都可以方便的访问到该内容。要实现这样的目的,必须使各个结构中的相同成员在整个联合体的偏移是一样的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 结构如下:

struct regionA {
int a;
int b;
char globalData[30]; // 各个阶段共用的,不希望被覆盖的
};

struct regionB{
char name[8];
char globalData[30];
};

struct regsionC{
char c;
char resv[7];
char globalData[30];
};

union sharedRegion {
struct regionA areaA;
struct regionB areaB;
struct regionC areaC;
...
};


之前都是通过人工手动计算保证globalData在各个结构中的偏移保持不变。 针对简单的结构可以算出来,复杂一点的就容易出错了,因此,我们需要一种方式保证偏移的准确性。默认头文件sys/_types.h中提供了 __builtin_offsetof的实现,可以支持快速计算成员的偏移.

1
2
3
4
5
6
7

#if defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 5 || __GNUC__ > 3)
#define __offsetof(type, field) __builtin_offsetof(type, field)
#else /* !(gcc >= 3.5) */
#define __offsetof(type, field) ((size_t)(&((type *)0)->field))
#endif /* (gcc >= 3.5) */

如此,我们就可以定义一个宏,再通过asset来保证各个结构体的偏移是一样的。

1
2
3
4
5
6
7
8
9

#define memberOffsetof(TYPE, MEMBER) ((size_t)(&((TYPE *)0)->MEMBER))


...
assert(memberOffsetof(struct regionA, globalData) == memberOffsetof(struct regionB, globalData));
assert(memberOffsetof(struct regionA, globalData) == memberOffsetof(struct regionC, globalData));
...

assert说明

1
2
3
4
#include <assert.h>
void assert( int expression );

assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行。

频繁的调用会极大的影响程序的性能,增加额外的开销。在调试结束后,可以通过在包含#include <assert.h>的语句之前插入 #define NDEBUG 来禁用assert调用,示例代码如下:

1
2
3
4
5
6
#include <stdio.h>
#define NDEBUG
#include <assert.h>


如果使用makefile, 那么可以在make的时候添加 -DNDEBUG选项

行动,才不会被动!

欢迎关注个人公众号 微信 -> 搜索 -> fishmwei,沟通交流。