【问题标题】:How is sizeof(*NULL) equal to 1 on 32-bit C compiler?sizeof(*NULL) 在 32 位 C 编译器上如何等于 1?
【发布时间】:2018-03-28 18:14:24
【问题描述】:

我最近了解到sizeof 不是一个函数,实际上是在编译时进行评估的。

但我仍然无法弄清楚sizeof(*NULL) 是如何等于 1 的。

编辑:我在这里专门谈论 gcc。

【问题讨论】:

  • 必须自己查一下:stackoverflow.com/questions/4141666/…
  • @Katianie - sizeof(NULL)sizeof(*NULL) 是非常不同的东西。
  • @Katianie 没错,我已经阅读了那篇文章,但找不到 sizeof(*NULL) 的参考资料
  • 我认为 sizeof(void) 是 GNU 特定的扩展
  • @UtkarshAgarwal 但它产生的输出为 1 这是一个违反 6.2.5 类型的 GCCism,the C standard 第 19 段:“The void 类型包含一组空值;它是不完整的对象类型,无法完成。"

标签: c pointers gcc


【解决方案1】:

这取决于编译器和标准库。在 GCC 和 glibc 中,NULL 定义为 (void*)0,而 GCC 有 an extension,它允许使用 sizeof(void) == 1void 指针进行指针运算。如果没有这个扩展,编译器会产生错误。

标准库也可以将NULL 定义为0。在这种情况下,sizeof(*NULL) 也是非法的。

【讨论】:

    【解决方案2】:

    Standard 不保证 sizeof(*NULL) 返回的值,这足以在实践中不使用此构造。

    您的代码使用实现定义的行为。

    7.173 宏是

    NULL
    

    扩展为实现定义的空指针常量

    这意味着标准不保证你的代码会被编译,更不用说产生特定的值了。

    在将宏 NULL 定义为 ((void*)0) 的系统上,您的代码将触发应视为错误的警告:

    prog.c:4:28: 错误:将“sizeof”无效应用到 void 类型 [-Werror=pointer-arith]

    Demo.

    【讨论】:

    • 没有NULL 的有效定义,sizeof(*NULL) 不违反约束。 NULL 可以是一个值为零的常量整数表达式(在这种情况下,取消引用非指针是无效的)这样的表达式转换为 void*(在这种情况下,*NULL 是输入void,它没有大小)。如果sizeof(*NULL) 至少没有触发警告,那么您的编译器不符合标准——默认情况下是 gcc。
    【解决方案3】:

    由于NULL 的类型为void *,这意味着*NULL 的类型为void。 C 标准不允许采用 void 的大小,尽管一些编译器将其作为扩展。

    GCC 中,它将void 的大小视为1,以允许对void * 进行指针运算。

    【讨论】:

    • C 标准不要求 NULL 的类型为 void *。它也可以是值为 0 的整数常量表达式。例如,#define NULL (2*4-8) 是合法的。
    • @EugeneSh。来自 C 规范:值为 0 的整数常量表达式,或转换为 void * 类型的此类表达式称为空指针常量。 如果将整数 0 转换为指针,它可能但是,不映射到地址 0。另请参阅C FAQ
    • @nwellnhof 我碰巧使用了一个地址0 是有效地址的系统。不过还是不知道怎么处理:)
    • @EugeneSh.:空指针常量的定义基本上是关于它的语法,而不是关于它的表示方式。实现可能在运行时使用全位一来表示空指针,但将整数常量 0 转换为 void* 仍必须产生空指针值。在大多数实现中,空指针表示为所有位为零,因此转换很简单(可能需要调整大小)。在其他实现中,转换必须做一些工作才能获得正确的结果。
    【解决方案4】:

    在“旧时” NULL 被定义为:

    #define NULL ((char *)0)
    

    所以使用*NULL,你会得到一个大小为 1 的字符。(你仍然可以看到隐藏在标题中的这样的定义,作为后备情况,现在,从 C90 开始,char 被替换为 @987654325 @)。

    我不认为它是一个有效的代码(NULL的间接,也只是取大小)。

    在某些编译器上,null 是 0l 或只是 0,这会在您的情况下出现错误。

    【讨论】:

    • 你在哪里看到这样的定义?
    • 如果是这样定义的,任何简单的赋值给另一个指针类型都会有问题。
    • 好的,这是旧的 C,现在是 ((void *) 0)0(令人难以置信的是,在普通系统上定义了 NULL 的包含数量。
    • @StoryTeller:什么? char 总是特别的,void 是 C 中相对较新的添加。
    • @EugeneSh。在Debian代码上,有一些这样定义的引用,有些定义是错误的,但无论如何:sources.debian.org/src/bash/4.4.18-1.1/lib/termcap/tparam.c/…
    猜你喜欢
    • 1970-01-01
    • 2013-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-18
    • 1970-01-01
    • 2012-11-18
    • 2012-10-22
    相关资源
    最近更新 更多