我问,因为在这个帖子中引发了讨论.
尝试在其他人的回复下使用评论进行严肃的来回讨论并不容易或有趣.所以我想听听我们的C专家的想法,一次不限制500个字符.
C标准几乎没有什么可说的NULL和空指针常量.我只能找到两个相关部分.第一:
3.2.2.3指针
具有值0的整型常量表达式,或者类型为void*的表达式,称为空指针常量.如果为指针的相等性分配或比较空指针常量,则将常量转换为该类型的指针.这种称为空指针的指针保证与指向任何对象或函数的指针不相等.
第二个:
4.1.5通用定义
宏是
Run Code Online (Sandbox Code Playgroud)NULL它扩展为实现定义的空指针常量;
问题是,可以NULL扩展为实现定义的空指针常量,该常量与3.2.2.3中列举的那些不同吗?
特别是,它可以定义为:
#define NULL __builtin_magic_null_pointer
Run Code Online (Sandbox Code Playgroud)
甚至:
#define NULL ((void*)-1)
Run Code Online (Sandbox Code Playgroud)
我对3.2.2.3的解释是,它指定0的整数常量表达式和0强制转换为类型void*的整型常量表达式必须是实现可识别的空指针常量的形式,但它不是意思是一份详尽的清单.我相信实现可以自由地将其他源构造识别为空指针常量,只要没有其他规则被破坏.
例如,可以证明这一点
#define NULL (-1)
Run Code Online (Sandbox Code Playgroud)
不是法律定义,因为在
if (NULL)
do_stuff();
Run Code Online (Sandbox Code Playgroud)
do_stuff() 不能被称为,而与
if (-1)
do_stuff();
Run Code Online (Sandbox Code Playgroud)
do_stuff()必须被召唤; 因为它们是等价的,所以这不是法律定义NULL.
但是标准说整数到指针的转换(反之亦然)是实现定义的,因此它可以定义-1到指针的转换,作为产生空指针的转换.在这种情况下
if ((void*)-1)
Run Code Online (Sandbox Code Playgroud)
会评价为假,一切都会好的.
那么别人怎么想呢?
我要求每个人特别记住中描述的"假设"规则2.1.2.3 Program execution.它是巨大的,有点迂回,所以我不会在这里粘贴它,但它实质上说,一个实现只需要产生与标准描述的抽象机器所需的相同的可观察副作用.它表示,只要程序的可观察副作用不被它们改变,任何优化,转换或编译器想要对程序执行的任何其他操作都是完全合法的.
因此,如果您希望证明特定的定义NULL不合法,您需要提出一个可以证明它的程序.任何一个像我一样公然打破标准中的其他条款,或者可以合法地检测编译器必须做的任何魔法来使奇怪的NULL定义工作.
Steve Jessop发现了一个程序检测方法的例子,NULL它没有被定义为3.2.2.3中两种形式的空指针常量之一,它是将常量字符串化:
#define stringize_helper(x) #x
#define stringize(x) stringize_helper(x)
Run Code Online (Sandbox Code Playgroud)
使用这个宏,人们可以
puts(stringize(NULL));
Run Code Online (Sandbox Code Playgroud)
并"检测"NULL不会扩展到3.2.2.3中的一个表单.这足以使其他定义非法吗?我只是不知道.
谢谢!
Ark*_*kku 12
在C99标准中,§7.17.3声明NULL"扩展为实现定义的空指针常量 ".同时§6.3.2.3.3将空指针常量定义为"具有值0的整数常量表达式,或者这样的表达式转换为类型void *".由于空指针常量没有其他定义,因此NULL必须将一致性定义扩展为整数常量表达式,其值为零(或此转换为void *).
进一步引用C FAQ问题5.5(重点补充):
C标准的4.1.5节声明NULL"扩展为实现定义的空指针常量",这意味着实现可以选择使用哪种形式的0以及是否使用`void*`cast; 见问题5.6和5.7.这里的"实现定义" 并不意味着NULL可能是#defined以匹配某些特定于实现的非零内部空指针值.
它很有道理; 由于标准要求在指针上下文中使用零整数常量来编译成空指针(无论机器的内部表示是否具有零值),因此NULL无论如何必须处理定义为零的情况.程序员不需要键入NULL来获取空指针; 它只是一种风格约定(并且可以帮助捕获错误,例如当在非指针上下文中使用NULL定义的时(void *)0).
编辑:这里混淆的一个原因似乎是标准使用的简洁语言,即它没有明确地说没有其他值可以被认为是空指针常量.但是,当标准说"...被称为空指针常量"时,这意味着确切地将给定的定义称为空指针常量.当(根据定义)标准定义什么是符合时,它不需要通过陈述不符合的内容来明确地遵循每个定义.
好吧,我找到了一种方法来证明这一点
#define NULL ((void*)-1)
Run Code Online (Sandbox Code Playgroud)
不是 NULL 的合法定义。
int main(void)
{
void (*fp)() = NULL;
}
Run Code Online (Sandbox Code Playgroud)
用 NULL 初始化函数指针是合法且正确的,而......
int main(void)
{
void (*fp)() = (void*)-1;
}
Run Code Online (Sandbox Code Playgroud)
...是需要诊断的约束违规。所以就这样了。
但__builtin_magic_null_pointer的定义NULL不会遇到这个问题。我仍然想知道是否有人能提出不能的理由。