【问题标题】:How to get the offset of a nested struct member in C?如何获取C中嵌套结构成员的偏移量?
【发布时间】:2017-03-17 09:17:06
【问题描述】:

info 结构中打印checksum 字段的偏移量的一种解决方案是使用宏typeofoffsetof

#include <stdio.h>
#include <stddef.h>
#include <stdint.h>

typedef struct
{
    struct {
       int a;
    } something;

    struct {
        int a;
        int b;
        int c[42];
        uint32_t checksum;
        int padding[10];
    } info[2];
    // ...
} S;

int main(void)
{   
    S s;
    printf("%lu\n", offsetof(typeof(s.info[0]), checksum));
    return 0;
}

不幸的是,typeof 不是标准的,所以我正在寻找一种更方便的方法来编写上面的示例,而不必在S 之外声明info

我为什么要这样做?

我有一个代表信息块的闪存内容的大结构。这些块中的每一个都有一个我想检查的校验和:

if (s.info[0].checksum != checksum(s.info[0], offsetof(typeof(s.info[0]), checksum))) {
    printf("Oops\n");
}

由于typeof,写作不可移植。

【问题讨论】:

  • 出于兴趣,您这样做是为了解决什么问题?
  • @Bathsheba 查看我的更新了解更多详情
  • 你总是可以给结构一个标签
  • offsetof 返回size_t 必须使用%zu 打印出来

标签: c struct typeof offsetof


【解决方案1】:

我不知道您为什么认为(标准 C 中不存在)typeof 是必需的。如果你给结构一个标签(information),这与offsetof 相得益彰:

#include <stddef.h>
#include <stdint.h>
#include <stdio.h>

typedef struct
{
    struct {
        int a;
    } something;

    struct information {
        int a;
        int b;
        int c[42];
        uint32_t checksum;
        int padding[10];
    } info[2];
    // ...
} S;

int main(void)
{
    printf("%zu\n", offsetof(S, info[0].checksum));
    printf("%zu\n", offsetof(S, info[1].checksum));
    printf("%zu\n", offsetof(struct information, checksum));
    printf("%zu\n", offsetof(S, info[0].checksum) - offsetof(S, info[0].a));
    return 0;
}

示例运行:

$ ./a.out
180
400
176
176

顺便说一句,don't bother with typedefs for structs. 他们没用。您不必相信我,但您可以相信 Peter van der Linden。

【讨论】:

  • 为什么我们必须相信 Peter van der Linden?这只是个人风格。我喜欢使用 typedefs,因为如果我打错字,它会告诉我未声明的标识符,而不是在代码的某些不同部分得到一个神秘的不兼容类型错误
  • 这很有趣。所以struct information 的范围是全局的。我不知道,这意味着我不能在某处声明另一个结构information。因此,在这种特殊情况下命名结构是一个非常糟糕的主意,因为我可能会发生冲突。
  • @nowox C 标准保证 s 和 s.info[0] 的开头相同(偏移量 0),因为它们是第一个成员。
  • @Jens 对于s.info[0] 是,但对于s.info[1] 不是
  • @Jens 我相信 Peter van der Linden,我刚买了这本书 :)
【解决方案2】:

使用指针算法。获取元素的地址,然后从结构的地址中减去。

((unsigned char *) &(s.info[0]).checksum - (unsigned char *) &(s.info[0]))

【讨论】:

  • 它可以工作并且它是可移植的,但我觉得它的可读性不如我最初的建议
  • @nowox 很好。每个熟练的 C 程序员都会知道你想要什么。如果你很担心,记录下一小段代码(// 获取结构中元素校验和的偏移量。),或者将其粘贴到函数中。
  • 请注意,减法结果的类型为ptrdiff_t,如果要打印则使用格式说明符%jd
  • 两个演员阵容丑得要命。 offsetof 可以做到这一点。
  • @Jens 主观的。我认为在这种情况下进行两次演员表很好。我同意,offsetof 会是更好的选择,但我将 OP 解释为他们不想使用任何宏或非标准行为,所以我这样回答。
猜你喜欢
  • 1970-01-01
  • 2011-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多