【问题标题】:Own offsetof implementation produces warning自己的 offsetof 实现产生警告
【发布时间】:2020-02-03 15:11:25
【问题描述】:

我写了一小段代码来了解 offsetof 宏在后台是如何工作的。代码如下:

#include <stdio.h>   
#include <stdlib.h>  

int main(void)
{
    /* Getting the offset of a variable inside a struct */
    typedef struct {
        int a;
        char b[23];
        float c;
    } MyStructType;

    unsigned offset = (unsigned)(&((MyStructType * )NULL)->c);

    printf("offset = %u\n", offset);

    return 0;
}

但是,如果我运行它,我会收到一条警告消息:

警告:从指针转换为不同大小的整数 [-Wpointer-to-int-cast]

但是,如果我查看 c 中的原始 offsetof 宏,代码如下所示:

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

int main(void)
{
    /* Getting the offset of a variable inside a struct */
    typedef struct {
        int a;
        char b[23];
        float c;
    } MyStructType;

    unsigned offset = offsetof(MyStructType, c);

    printf("offset = %u\n", offset);

    return 0;
}

那么为什么我在转换为 unsigned 时会收到警告?它似乎是 offsetof 宏的类型。这让我很困惑。

【问题讨论】:

  • of different size 表示指针的值可能不适合unsigned。你应该投到uintptr_t
  • 我猜?您在 64 位系统上,其中指针为 64 位宽,unsigned(又名unsigned int)为 32 位宽。请改用uintmax_tuintptr_tsize_t
  • 请注意,&amp;((MyStructType * )NULL)-&gt;c 取消引用 NULL 指针并且是未定义的行为。
  • 您可能需要转换为uintptr_t,然后转换为size_t(因为offsetof 应该产生size_t)。
  • @Meerkat 只有当uintptr_t 值不适合size_t 时才会出错。但是由于size_t可以保存任何对象的大小,它也可以保存结构对象的任何成员的偏移量。

标签: c macros


【解决方案1】:

正如 mch 所评论的,unsigned 不是正确的类型;它在几乎所有现实世界的系统上都是 32 位的。 offsetof 宏应该产生size_t 类型的结果,这是您“应该”在此处转换的结果。我认为您对将结果存储到unsigned 类型的对象中的代码感到困惑;只要他们确定值很小就可以,但这并不意味着表达式offsetof(MyStructType, c); 的类型是unsigned。 C 允许您默默地将较大的整数类型分配给较小的整数类型。

但是,无论您做什么,这不是offsetof 的有效实现并且具有未定义的行为(通过将-&gt; 应用于无效指针)。在没有 UB 的情况下,您获得工作 offsetof 的方式是 #include &lt;stddef.h&gt;

【讨论】:

  • 所以在将较大的整数类型静默分配给较小的整数类型的情况下,C 不会产生警告?
  • 注意:无论如何,您的编译器可能会以这种方式实现 offsetof,但他们可以这样做,因为他们知道自己的编译器是如何工作的。您不允许这样做,因为有人可能会尝试使用无法以这种方式工作的编译器。
  • @user253751:不,它没有,因为 C 要求 offsetof 的结果是一个整数常量表达式,而这不是一个。
  • @ R.. GitHub STOP HELPING ICE:谢谢你的回答,但我不太明白你的解释:(
  • @R..GitHubSTOPHELPINGICE 有 get out 子句“实现可以接受其他形式的常量表达式。”一些实现实际上确实使用地址运算符实现offsetof,例如MSVC。
猜你喜欢
  • 2015-02-06
  • 1970-01-01
  • 2021-11-25
  • 2018-12-25
  • 2015-07-22
  • 2011-06-02
  • 2011-05-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多