当使用 int 变量时为什么会收到警告,但使用整数常量时不会收到警告?

4

我有一段代码的两个版本。第一个版本使用一个 int 变量作为条件测试表达式的一部分,第二个版本则使用一个整数常量 - 两者都表示相同的整数值 - 24

1. 代码

#include <stdio.h>

int main()
{
    int var = 24;

    if((!var) == NULL)
    {
        printf("1");
    }
}

2. 代码

#include <stdio.h>

int main()
{
    if((!24) == NULL)
    {
        printf("1");
    }
}

当我尝试编译第一个版本时,我收到了来自gcc的警告:

警告:指针和整数之间的比较

以及来自clang的:

警告:指针和整数之间的比较('int'和'void *')[-Wpointer-integer-compare]

但是当我使用相同的值作为整数常量编译几乎相同的代码时,一切都很好。为什么?


我的研究成果:

我查阅了C18的6.4.4章节“常量”:

首先,在第/2和/3小节下:

“2-每个常量都应有一个类型,并且常量的值应在其类型可表示的范围内。”

“3-每个常量都有一个类型,由其形式和值确定,详见后文。”

其次,在第/5小节下:

“整数常量的类型是其对应列表中第一个可表示其值的类型。”

以下是该列表:

list

因此,没有后缀并且相对于可表示值24的整数常量应具有类型int
我理解警告本身,并知道在大多数实现中,NULL通常扩展为(void*) 0。因此,抛出此警告是合理的。
但是,为什么使用相同的值作为整数常量时不会出现警告?

在指针中使用NULL,不要在非指针操作中使用NULL。这是一个空指针常量。请参阅C11 [§7.19 Common definitions <stddef.h>](http://port70.net/~nsz/c/c11/n1570.html#7.19):宏为 `NULL`它扩展为实现定义的空指针常量; 和... - Jonathan Leffler
4
编译器将您的字面值(!24)视为(0),这是一个有效的指针常量(实际上是唯一有效的指针常量)。请参见此处 - Adrian Mole
3
!24 等于零,零可以与 NULL 进行比较(它可以直接转换为 void *)。 - Jonathan Leffler
2
请注意,if((!0) == NULL)也应该引发警告。 - ad absurdum
已确认,Clang和GCC会警告(!0) == NULL但不会警告(!1) == NULL - Eric Postpischil
1个回答

6
从C11 6.3.2.3/3:
一个值为0的整数常量表达式,或者将这样的表达式强制转换为void *类型,称为null指针常量。
关于等号运算符==和!=,从6.5.9/2中可以得知:
以下情况之一必须成立:
...
- 一个操作数是指针,另一个是null指针常量。
需要注意的是,整数常量表达式不仅限于整数常量(0,42等),还可以包括对它们进行操作的运算符,如5+5-10。
!24是一个值为0的整数常量表达式,因此属于null指针常量。==运算符允许在指针和null指针常量之间进行比较,这使得(!24) == NULL成为一个有效的比较。
在第一个例子中,!var不是一个整数常量表达式,因为它包含一个变量操作数,因此不能与指针进行比较。
注意:在大多数实现中,NULL被定义为(void*)0,因此上述内容是正确的。但是,标准允许将其定义为任何null指针常量,例如0。如果是这种情况,则比较(!var) == NULL将编译通过,因为它与(!var) == 0相同。

1
如果问题中的值为0而不是24,编译器会生成一个警告。 - dbush

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接