C结构内存布局偏移

时间:2017-06-15 22:26:32

标签: 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;
}

获得指向b s1的指针后,我尝试使用指针算法来访问s1->other的成员。我尝试过以下方法:

// 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开始。

3 个答案:

答案 0 :(得分:5)

这一行:

struct s2 *p2 = (struct s2*) b + 64;

应更改为:

struct s2 *p2 = *(struct s2**) (b + 64);

添加了括号,因为强制转换的优先级高于+

使用双指针代替常规指针,因为正如@ M.M所说,b + 64处的对象是struct s2 *(不是struct s2)。

强制性免责声明:

我认为你只是为了练习而做。

你不应该在实际项目中使用这些技巧。如果你绝对必须,至少使用offsetof来避免任何潜在的填充问题。

答案 1 :(得分:4)

正如@HolyBlackCat所指出的,显而易见的问题是+ - 运算符上的类型转换优先级,因此(struct s2*) b + 64等同于(struct s2*) (b + 64*sizeof(struct s2))

无论如何,我会避免使用指针算术来获取下一个数据成员,因为可能存在填充问题,并且由于硬编码64。 (编译器可以自由添加填充字节,因此你不能依赖64,但我认为你知道这一点。)

我宁愿使用offsetof来获取指向相应struct s1所属的b - 对象的指针,然后只需使用->other来获取struct s2 {1}} - 指针:

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;
}

答案 2 :(得分: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