C 程序检测NULL是用整数还是指针类型定义的方法?
C允许将C 程序检测NULL是用整数还是指针类型定义的方法?,c,language-lawyer,C,Language Lawyer,C允许将NULL定义为任何空指针常量,换句话说,任何计算结果为0的整数常量表达式,或将此类表达式转换为void*。我的问题是,定义的选择是否真的很重要,也就是说,一个正确的程序是否取决于使用哪个定义。出于这个问题的目的,我想忽略像NULL被传递给变量函数或缺少原型的函数这样的问题,因为我已经分别处理过了。让我们假设sizeof NULL==sizeof(void*)和sizeof NULL==sizeof(T)对于某些整数类型T,因此sizeof不足以回答NULL是否具有指针类型的问题 显然,C
NULL
定义为任何空指针常量,换句话说,任何计算结果为0的整数常量表达式,或将此类表达式转换为void*
。我的问题是,定义的选择是否真的很重要,也就是说,一个正确的程序是否取决于使用哪个定义。出于这个问题的目的,我想忽略像NULL
被传递给变量函数或缺少原型的函数这样的问题,因为我已经分别处理过了。让我们假设sizeof NULL==sizeof(void*)
和sizeof NULL==sizeof(T)
对于某些整数类型T
,因此sizeof
不足以回答NULL
是否具有指针类型的问题
显然,C11提供了一种方法来区分NULL
或任何其他表达式的类型:\u Generic
关键字
C99还提供了一种看似可靠的模糊方法:
int null_has_ptr_type()
{
char s[1][1+(int)NULL];
int i = 0;
return sizeof s[i++], i;
}
是否有任何其他方法可以通过一致性C程序确定
NULL
的类型?在C89中工作的任何字符串?获取NULL的字符串定义,然后根据需要执行完整的检查。下面是一个非常简单的例子:
#define XSTR(x) #x
#define STR(x) XSTR(x)
if (STR(NULL)[0] == '(') {
...
}
但是我不知道如何处理从中产生的
\uu null
。您不能将宏字符串化并查看字符串吗
# include <stddef.h>
# include <stdio.h>
# include <string.h>
# define STRINGIFY(x) STRINGIFY_AUX(x)
# define STRINGIFY_AUX(x) #x
int main(void)
{
const char *NULL_MACRO = STRINGIFY(NULL);
if (strstr("void", NULL_MACRO) != NULL)
puts("pointer");
else
puts("integer");
}
NULL
不能类似于(int)((void*)0)
,因为标准没有规定转换为整数类型的空指针常量仍然是空指针常量
此外,该标准还规定了整数常量表达式(C11,6.6/6):
整型常量表达式117)应为整型,且仅应具有整型常量、枚举常量、字符常量、结果为整型常量的表达式的大小、
表达式的对齐操作数,和浮点常量,它们是强制转换的直接操作数。整数常量表达式中的强制转换运算符只能将算术类型转换为整数类型,除非作为操作数的一部分转换为
或\u
运算符
编辑:实际上,这不适用于以下情况:
#定义空值(sizeof(void*)-sizeof(void*))
(感谢您的注意)这不能用一种简单的方式进行检查,因为OP需要一些工作(简单的解析)
编辑2:还有注释正确指出的
typedef
。通过问题、答案和注释,我认为我们建立了:
\u Generic
)typedef
,串接方法是一条死胡同因此,答案似乎是没有可靠的pre-C11方法,也似乎没有有效的pre-C99方法。这里有一个模糊的方法:如果程序使用表达式
&*NULL
,这将不会编译为具有整数类型的NULL
,但如果NULL
具有指针类型,则会编译
C99有针对这种特殊情况的措辞:
如果[code>&运算符的]操作数是一元*
运算符,该运算符和&
运算符都不会被计算和
结果就像两个都被省略了一样,除了
运算符仍然适用,结果不是左值
没有违反对运算符的约束:
&
的操作数是一元*
运算符的结果,一元*
运算符的操作数具有指针类型(我们假设NULL
是这样定义的)。char c=NULL如果NULL
的类型为void*
(因此存在强制转换),则code>会生成编译器警告。函数NULL\u的类型是否有效?在我的计算机上,这两种情况下都返回0。returnsizeof s[i++],i
将返回i。在这种情况下,您需要一个支持C99的C编译器,包括VLA和sizeof的正确实现。如果s
是VLA,则计算i++
,否则不计算。如果NULL是指针,s
将是一个VLA,如果它是一个int或类似的东西,则不是。。。GCC在这两种情况下给出不同的警告@Kirilenko@R..:表示VLA支持“损坏”。4.5说没问题。(4.6.1作品)@R…,我提出了一个非常简单的理由;这适用于任意级别的宏间接寻址吗?e、 g.#定义空值(NULL1
,#定义空值(NULL1)(NULL2)
,#定义空值(null0
?我不认为…@R…:这个定义似乎已经确定,可以在理论上检测出来。是否实际需要一个健壮的解决方案?@Oli:no,实际上我更感兴趣的是应用程序可能会无意中依赖于定义的方式。@R..,因为您排除了可变函数(其中的差异可能导致UB),我看不出无意中依赖的合理情况。如果有一个(特别是(void*)0
对于C实现来说是常见的,对于C++来说是不一致的),我希望它现在能够得到解决,或者至少是民间传说。值为0的整型常量表达式在将其强制转换为void*
时仍然是空指针常量。但是,将指针强制转换为整数类型永远不会产生整数常量表达式。显然,似乎很难处理的情况是#define NULL u NULL
,其中u NULL
是编译器的固有特性。@R。。我的上一个
# undef NULL
# define NULL 0