C编译器应该警告"char c = NULL"吗?

duo*_*zmo 5 c null gcc casting gcc-warning

拿这个简短的C文件,nulltest.c,打印出"Hey":

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

int main() {
  char c = NULL;
  c = 'e';
  printf("H%cy\n", c);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我的理解是在C中,NULL 应该扩展为空指针常量,这将使char c = NULL指针隐式转换为整数.但是,在gcc 4.8中编译时:

$ gcc --version
gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
$ gcc -Wall -Wconversion nulltest.c
$
Run Code Online (Sandbox Code Playgroud)

我没有得到任何警告.

另一方面,gcc和clang的先前版本都警告相同的代码:

$ gcc --version
gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-3)
$ gcc nulltest.c
nulltest.c: In function ‘main’:
nulltest.c:5: warning: initialization makes integer from pointer without a cast
Run Code Online (Sandbox Code Playgroud)

在Mac OS X 10.9上:

$ clang --version
Apple LLVM version 5.1 (clang-503.0.38) (based on LLVM 3.4svn)
$ clang nulltest.c
nulltest.c:5:8: warning: incompatible pointer to integer conversion initializing
      'char' with an expression of type 'void *' [-Wint-conversion]
  char c = NULL;
       ^   ~~~~
Run Code Online (Sandbox Code Playgroud)

对于gcc 4.4和4.8,我相信stddef.h的相关副本中相关行读取#define NULL ((void *)0).

为什么一个版本的gcc警告而不是另一个?

Kei*_*son 8

他们应该警告吗?当然.他们需要吗?没有.

空指针常数是指针类型的不一定; 事实上它通常不是.(是的,这和你想象的一样奇怪.)

空指针常量是值为0的常量整数表达式,或者是这样的表达式void*.所以实现可能有:

#define NULL 0
Run Code Online (Sandbox Code Playgroud)

遗憾的是,这意味着它不会报告错误

char c = NULL;
Run Code Online (Sandbox Code Playgroud)

实施还可以:

#define NULL ((void*)0)
Run Code Online (Sandbox Code Playgroud)

这将避免这个特定问题 - 但并非所有实现都这样做.(旁注:在C++中,((void*)0)不是有效的空指针常量.)

编译器可以使用其他技巧来检测此类逻辑错误.例如:

enum { __NULL__ };
#define NULL __NULL__
Run Code Online (Sandbox Code Playgroud)

甚至:

#define NULL __magic_builtin_null_pointer_constant__
Run Code Online (Sandbox Code Playgroud)

NULL仍然扩展为int值为零的类型的表达式,但编译器可能会检测到此特定表达式的使用(如果它在内部保留该信息)并发出警告.

但最终由您作为程序员来避免这种特殊错误.不幸的是,您无法依靠编译器为您检测它.

另一个含义是,如果需要将空指针作为参数传递给具有可变数量参数的函数,则无法安全地传递NULL; 你必须将它强制转换为适当的指针类型.该execl*()功能是这是最常见的例子.

该标准定义了术语空指针常量,但它没有说空指针常量是具有指针类型的表达式.表达式0总是类型int- 并且它总是一个空指针常量,即使在非指针上下文中使用时也是如此

int n = 0;
Run Code Online (Sandbox Code Playgroud)

(并且它是八进制常量.)术语空指针常量需要被理解为由标准定义的单个概念,而不是作为其含义源自其组成单词的短语.