C结构内存布局偏移量
我处理的结构如下所示:C结构内存布局偏移量,c,memory,struct,C,Memory,Struct,我处理的结构如下所示: struct s1 { struct s1 *next; char a[64]; char b[64]; struct s2 *other; }; struct s2 { uint32_t x; uint32_t y; } // Assuming we have the following struct s1 *p1 = ... char *b = p1->b; // Offset to get to s2 struct s2 *p2
struct s1 {
struct s1 *next;
char a[64];
char b[64];
struct s2 *other;
};
struct s2 {
uint32_t x;
uint32_t y;
}
// Assuming we have the following
struct s1 *p1 = ...
char *b = p1->b;
// Offset to get to s2
struct s2 *p2 = (struct s2*) b + 64;
// Access members
uint32_t result = p2->x;
获得了一个指向s1
的b
的指针后,我试图使用指针算法访问s1->other
的成员。我尝试了以下方法:
struct s1 {
struct s1 *next;
char a[64];
char b[64];
struct s2 *other;
};
struct s2 {
uint32_t x;
uint32_t y;
}
// Assuming we have the following
struct s1 *p1 = ...
char *b = p1->b;
// Offset to get to s2
struct s2 *p2 = (struct s2*) b + 64;
// Access members
uint32_t result = p2->x;
我不认为填充是个问题,因为我从b
这一行开始:
struct s2 *p2 = (struct s2*) b + 64;
应改为:
struct s2 *p2 = *(struct s2**) (b + 64);
添加括号是因为强制转换的优先级高于+
使用双指针代替常规指针是因为,@M.M说,b+64
处的对象是struct s2*
(而不是struct s2
)
强制性免责声明: 我想你这样做只是为了练习
你不应该在实际项目中使用这些技巧。如果一定要这样做,至少要使用
offsetof
来避免任何潜在的填充问题。正如@HolyBlackCat所指出的,明显的问题是类型强制转换优先于+
-运算符,这样(struct s2*)b+64
相当于(struct s2*)(b+64*sizeof(struct s2))
无论如何,我会避免使用指针算术来获取下一个数据成员,因为可能存在填充问题以及硬编码的64
。(编译器可以自由添加填充字节,因此您不能依赖64
,但我想您已经意识到了这一点)
我宁愿使用offsetof
来获取指向相应b
所属的struct s1
-对象的指针,然后简单地使用->other
来获取struct s2
-指针:
struct s1 {
struct s1 *next;
char a[64];
char b[64];
struct s2 *other;
};
struct s2 {
uint32_t x;
uint32_t y;
};
int main() {
struct s2 os2 = { 10, 20 };
struct s1 os1 = { NULL, "asdf", "asdf", &os2 };
char *b = os1.b;
struct s1 *ps1 = (struct s1*)(b - offsetof(struct s1, b));
struct s2 *p2 = ps1->other;
// Access members
uint32_t result = p2->x;
return 0;
}
你的问题是:
// Offset to get to s2
struct s2 *p2 = (struct s2*)b + 64; // Wrong!! casting b as a s2*
// you are getting the address of
// the 65tth element of an array of s2
// starting at b.
struct s2* p2 = (struct s2*)((char*)&(p1->b) + 64); // note the char* cast here.
// it will make this work even when b
// is not a char array
即使没有强制,此代码也会调用未定义的行为。这是一个明显的禁忌。像这样疯狂地抛出指针违反了有效类型(也称为严格别名)规则。@Olaf我不完全相信发布的代码违反了严格别名,因为使用了
char*
。然而,我根本不需要相信发布的代码是一种非常非常糟糕的方法。为什么不使用联合呢?你使用什么样的C语言、编译器和平台?你想要的部分是由offsetof
-为什么不使用它?@AndrewHenle:ff。简单地说:当强制转换到char*
并以char
的身份访问时,一般不允许做相反的事情。现代编译器将利用这一点。代码调用UB。无需进一步研究(或帮助)。