C语言中的空与零

C语言中的空与零,c,null,null-pointer,C,Null,Null Pointer,我最近读过 简言之,在回答中提到,不建议使用NULL替换0的值,这将导致UB 但简而言之,假设if(!ptr)//ptr是指针并不是完全错误的 我知道问题的内容是不同的,但是如果(!ptr)是真的,那么如何解释使用NULL替换0是错误的? 因为if(!ptr)等同于if(ptr==0)(我假设这是正确的,不确定) 另外,我使用了if(ptr==0),它对我来说从来没有出错过(检查ptr是否为NULL),并且将0分配给指针ptr,当我调试代码时ptr为NULL。这两种体验安全吗?来自: 要将指针初

我最近读过

简言之,在回答中提到,不建议使用NULL替换
0
的值,这将导致UB

但简而言之,假设
if(!ptr)//ptr是指针并不是完全错误的

我知道问题的内容是不同的,但是如果(!ptr)
是真的,那么如何解释使用NULL替换0是错误的? 因为
if(!ptr)
等同于
if(ptr==0)
(我假设这是正确的,不确定)

另外,我使用了
if(ptr==0)
,它对我来说从来没有出错过(检查
ptr
是否为NULL),并且
0
分配给指针
ptr,当我调试代码时
ptr
为NULL
。这两种体验安全吗?

来自:

要将指针初始化为null或将null值分配给现有指针,可以使用null指针常量(
null
,或任何其他值为零的整数常量)

[我的重点]

因此整数常量
0
是一个有效的空指针常量

但请注意,这并不意味着所使用的硬件平台上的实际空值等于
0
,它只意味着编译器接受
0
作为依赖于系统的空指针常量的别名

此外,空指针总是“false”,非空指针总是“true”,这就是为什么像
if(ptr)
if(!ptr)
这样的条件工作得很好

我知道问题的内容不同,但这怎么可能呢 解释了使用NULL替换0是错误的,而
如果(!ptr)
为真?因为
if(!ptr)
等同于
if(ptr==0)
(I 假设这是对的,不确定)

if(!ptr)
if(!ptr!=0)
通过
if
语句的语义等价,这与
if(ptr==0)
通过
语句的语义等价
=,以及带有指针操作数的
=
运算符。这是很好的一致性,但它并不是根据您所知道的任何关于整数运算的知识。指针上的操作有自己的规则集


而这正是我想要的。由于值为零的整数常量(源代码构造)是空指针常量,因此根据定义,它与所有空指针值进行比较。这完全没有说明任何类型的null指针值的表示,也没有说明
null
宏扩展到的表达式的类型,或关于将源代码中未表示为值为零的整数常量的任何特定空指针值转换为整数所产生的值。

null
是一个宏。它是一个“实现定义的空指针常量”;C17dr§7.19 3

值为0的整型常量表达式或转换为类型
void*
的此类表达式称为空指针常量。C17dr§6.3.2.3

因此
NULL
可能具有
void*
int
long
unsigned
long
等类型

0
是一个
int
常量

一切正常。

赋值:下面两个都将
p,q
赋值给某个空指针

代码比较:p==q为真,因为所有空指针相等。所有空指针并不等于任何对象的地址<代码>!p
!q
都是1

当它不正常时。

函数参数

NULL
的类型及其大小由实现定义

printf("%d\n", 0);            // OK - %d expects an int
printf("%d\n", NULL);         // Not OK, NULL could be long, void *, etc.
printf("%p\n", NULL);         // Not OK, NULL could be int, long, long long
printf("%p\n", (void*) NULL); // OK - %p expects a void*
_Generic((NULL), \
  void *: "void *", \
  int: "int", \
  long: "long", \
  default: "TBD")
\u Generic()

下面是实现定义的结果

printf("%d\n", 0);            // OK - %d expects an int
printf("%d\n", NULL);         // Not OK, NULL could be long, void *, etc.
printf("%p\n", NULL);         // Not OK, NULL could be int, long, long long
printf("%p\n", (void*) NULL); // OK - %p expects a void*
_Generic((NULL), \
  void *: "void *", \
  int: "int", \
  long: "long", \
  default: "TBD")
宏比较

下面的错误导致“错误:运算符“*”没有正确的操作数”<代码>#如果!0
正常

#if !NULL
#error foo
#endif

ptr=0
正常吗?我的意思是,使用这个初始化而不是
ptr=NULL
是正确的吗?实现可能保证也可能不保证所有
printf
示例的任何内容,但是那些指定以某种方式定义
NULL
的示例需要以有意义的方式处理第二行或第三行“not ok”(不正常),取决于它们指定
NULL
的精确程度。首先将
int
0转换为一个指针,一个NULL指针,然后赋值。定义明确。第二个将任何类型的
NULL
转换为指针,一个NULL指针,然后赋值。定义也很明确。使用其中一种,最好按照您组的编码标准/风格进行编码。@supercat“实现可能保证也可能不保证所有printf示例的任何内容,”-->printf的
printf有什么不保证的内容(“%d\n”,0)?@chux:他们会被要求提供一些担保,但不是全部。