有没有办法在编译时确定成员偏移量?

时间:2014-01-08 16:20:43

标签: c gcc

我发现在调试时我花了很多时间试图确定结构的成员偏移量。我想知道是否有一种快速的方法来确定编译时大型结构中成员的偏移量。 (注意:我知道创建编译时断言的几种方法,即偏移量在给定范围内,我可以进行二进制搜索以获得正确的值,但我正在寻找更高效的东西)。我正在使用相当新版本的gcc来编译 C 代码。

3 个答案:

答案 0 :(得分:7)

offsetof就是你想要的,它是编译时间。 C99 draft standard部分7.17 通用定义 3 表示:

  

offsetof(type,member-designator)

     
    

扩展为一个整数常量表达式,其类型为size_t,值为     这是以字节为单位的偏移量[...]

  

上面链接的手册页有以下示例代码,演示了它的用法:

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

样本输出,可能会有所不同:

 offsets: i=0; c=4; d=8 a=16
 sizeof(struct s)=16

参考常量表达式6.6 常量表达式和段落 2 中说明:

  

可以在转换期间而不是运行时评估常量表达式   因此可以在常数可能的任何地方使用。

更新

在OP澄清后,我想出了一个使用-O0 -fverbose-asm -S grep 的新方法,代码如下:

#include <stddef.h>

struct s {
        int i;
        char c;
        double d;
        char a[];
    };

int main()
{
    int offsetArray[4] = { offsetof(struct s, i ), offsetof( struct s, c ), offsetof(struct s, d ), offsetof(struct s, a )  } ;

    return 0 ;
}

使用构建:

gcc -x c -std=c99 -O0 -fverbose-asm  -S main.cpp && cat main.s | grep offsetArray

示例输出( live example ):

movl    $0, -16(%rbp)   #, offsetArray
movl    $4, -12(%rbp)   #, offsetArray
movl    $8, -8(%rbp)    #, offsetArray
movl    $16, -4(%rbp)   #, offsetArray

答案 1 :(得分:2)

好的,在这里回答我自己的问题:注意:我想在编译时确定偏移量,也就是说,我不想运行代码(我也可以只编译我需要的文件,而不是整个系统):以下内容可以剪切并粘贴给感兴趣的人:

#include <stddef.h>

#define offsetof_ct(structname, membername) \
void ___offset_##membername ## ___(void) { \
        volatile char dummy[10000 + offsetof(structname, membername) ]; \
        dummy[0]=dummy[0]; \
}

struct x {
        int a[100];
        int b[20];
        int c[30];
};

offsetof_ct(struct x,a);
offsetof_ct(struct x,b);
offsetof_ct(struct x,c);

然后运行:

~/tmp> gcc tst.c -Wframe-larger-than=1000
tst.c: In function ‘___offset_a___’:
tst.c:16:1: warning: the frame size of 10000 bytes is larger than 1000 bytes
tst.c: In function ‘___offset_b___’:
tst.c:17:1: warning: the frame size of 10400 bytes is larger than 1000 bytes
tst.c: In function ‘___offset_c___’:
tst.c:18:1: warning: the frame size of 10480 bytes is larger than 1000 bytes
/usr/lib/gcc/x86_64-redhat-linux/4.5.1/../../../../lib64/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: ld returned 1 exit status

然后我减去10000以获得偏移量。注意:我尝试将#pragma GCC diagnostic warning "-Wframe-larger-than=1000"添加到文件中,但它并不喜欢它,因此必须在命令行中指定它。

约翰

答案 2 :(得分:0)

这应该做:

#define OFFSETOF(T, m) \
  (size_t) (((char *) &(((T*) NULL)->m)) - ((char *) ((T*) NULL)))

这样称呼:

size_t off = OFFSETOF(struct s, c);