Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xcode/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C结构内存布局偏移量_C_Memory_Struct - Fatal编程技术网

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。无需进一步研究(或帮助)。