struct a
{
struct b
{
int i;
float j;
}x;
struct c
{
int k;
float l;
}y;
}z;
谁能解释我如何找到的偏移量,int k
以便我们可以找到的地址int i
?
用于查找从 的开头或从 的开头offsetof()
的偏移量。z
x
offsetof()
- 结构成员的偏移量
概要
#include <stddef.h>
size_t offsetof(type, member);
offsetof()
返回字段成员从结构类型开始的偏移量。
例子
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
int
main(void)
{
struct s {
int i;
char c;
double d;
char a[];
};
/* Output is compiler dependent */
printf("offsets: i=%ld; c=%ld; d=%ld a=%ld\n",
(long) offsetof(struct s, i),
(long) offsetof(struct s, c),
(long) offsetof(struct s, d),
(long) offsetof(struct s, a));
printf("sizeof(struct s)=%ld\n", (long) sizeof(struct s));
exit(EXIT_SUCCESS);
}
如果您使用 GCC 编译,您将在 Linux 上获得以下输出:
offsets: i=0; c=4; d=8 a=16
sizeof(struct s)=16
自提出问题以来已经 3 年了,为了完整起见,我正在添加我的答案。
获取结构成员偏移量的hacky方法是这样的
printf("%p\n", (void*)(&((struct s *)NULL)->i));
它看起来不漂亮,我想不出纯 C 中的任何东西(它可以让你得到成员的偏移量,而不知道关于结构的任何其他内容。我相信offsetof
宏是以这种方式定义的。
作为参考,这种技术在 linux 内核中使用,查看container_of
宏:
http://lxr.free-electrons.com/source/scripts/kconfig/list.h#L18
更详细的解释可以在这篇文章中找到:
struct a foo;
printf("offset of k is %d\n", (char *)&foo.y.k - (char *)&foo);
printf("offset of i is %d\n", (char *)&foo.x.i - (char *)&foo);
foo.x.i
i
在 structx
中引用struct 中的字段foo
。
&foo.x.i
给你字段的地址foo.x.i
。同样,&foo.y.k
给你的地址foo.y.k
;
&foo
给你 struct 的地址foo
。
foo
从 的地址中减去 的地址 得到从到foo.x.i
的偏移量。foo
foo.x.i
正如 Gangadhar 所说,您可以使用offsetof()
宏而不是我给出的指针算法。但最好先了解指针算法。
正如已经建议的那样,您应该使用offsetof()
宏 from <stddef.h>
,它将偏移量作为size_t
值产生。
例如:
#include <stddef.h>
#include <stdio.h>
#include "struct_a.h" /* Header defining the structure in the question */
int main(void)
{
size_t off_k_y = offsetof(struct c, k);
size_t off_k_z = offsetof(struct a, y.k);
size_t off_i_x = offsetof(struct b, i);
size_t off_i_z = offsetof(struct a, x.i);
printf("k = %zu %zu; i = %zu %zu\n", off_k_y, off_k_z, off_i_x, off_i_z);
return 0;
}
示例输出:
k = 0 8; i = 0 0
要找到偏移量,这是我们可以解决的一种方法。
struct a{
struct b
{
int i;
float j;
}x;
struct c
{
int k;
float l;
}y;
}z;
int main(){
struct a* foo = &z;
printf("%d\n", foo); //address of z
printf("%d\n", &(foo->y)); //address of z.y
printf("%d\n", &( (&(foo->y))->k )); //address of z.y.k
int offset_k = (char*)&( (&(foo->y))->k ) - (char*)foo ;
printf("%d\n", offset_k);
return 0;
}
输出将与此类似:
4225552 //address of z
4225560 //address of z.y
4225560 //address of z.y.k
8 //offset
在这种特殊情况下,由于 int i 是结构的第一个成员,因此结构的基地址也将是 int i 的基地址。否则,您可以以类似的方式计算 int i 的偏移量。
int offset_i = (char*)&( (&(foo->x))->i ) - (char*)foo; //0 in this case
注意:偏移量将是负数或正数,具体取决于您如何定义它(如果它是关于基地址或成员 zyk)。在这里,它被定义为相对于 struct 的基地址。
这是一个通用的解决方案:
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
# define GNUC_PREREQ(minMajor, minMinor) \
((__GNUC__ << 16) + __GNUC_MINOR__ >= ((minMajor) << 16) + (minMinor))
#else
# define GNUC_PREREQ 0
#endif
#if GNUC_PREREQ(4, 0)
# define OFFSETOF(type, member) ((int)__builtin_offsetof(type, member))
#else
# define OFFSETOF(type, member) ((int)(intptr_t)&(((type *)(void*)0)->member) )
#endif