考虑以下代码:
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
//#include <float.h> //uncomment so it can be compiled
#define GETMAX(variable) _Generic \
( \
(variable) \
, bool : 1 \
, char : CHAR_MAX \
, unsigned char : UCHAR_MAX \
, signed char : SCHAR_MAX \
, unsigned short : USHRT_MAX \
, signed short : SHRT_MAX \
, unsigned int : UINT_MAX \
, signed int : INT_MAX \
, unsigned long : ULONG_MAX \
, signed long : LONG_MAX \
, unsigned long long : ULLONG_MAX \
, signed long long : LLONG_MAX \
, float : FLT_MAX \
, double : DBL_MAX \
, long double : LDBL_MAX \
)
int main(int argc, char **argv)
{
(void)argv;
uint_fast8_t a;
if( argc>GETMAX(a) )
{ printf("argc too big\n"); }
else
{ printf("argc small enough\n"); }
return 0;
}
它不会用gcc编译,也不会用clang编译(不知道其他编译器),gcc会用error: ‘FLT_MAX’ undeclared (first use in this function) ...
编译(即使没有任何警告标志),但为什么呢?我使用的GETMAX
是一个整数,FLT_MAX
的值与此无关,在我的机器上,只需要UCHAR_MAX
。行if( argc>GETMAX(a) )
应该变成if( argc>UCHAR_MAX )
的等价物(编译后,FLT_MAX
在预处理器之后仍然存在),使所有其他限制无关紧要。
修复很容易,只需添加#include <float.h>
,问题是为什么会这样。
1条答案
按热度按时间quhf5bfb1#
C期望表达式中使用的所有标识符都被声明。1虽然可能重新设计语言以忽略某些地方未声明的标识符,但要求声明有助于避免错误。
还有一些地方可能会忽略未知的标识符。例如,考虑:
1 || x
的值是1,而不管x
的值是什么。但是,如果typedef int x;
在此之前的代码中,则将是错误的,因为||
的右操作数必须是语法上的 logical-AND-expression,并且类型不是表达式。因此,如果x
未声明,编译器就无法检查1 || x
是否是C标准规则定义的有效表达式。另一个例子是
int a[3]; return sizeof a[x];
,如果接受它,它将返回int
的大小,而不管x
。在这里,C标准说x
不被计算。然而,它必须被宣布。另一个例子是return 0; x;
。在这里,程序控制没有办法到达x
,所以它永远不会被评估。然而,它必须被宣布。类似地,在
_Generic
中,:
后面的语法实体必须是 assignment-expression,除非声明了其中的标识符,否则编译器无法检查。脚注
1在过去,在调用中用作函数指示符的标识符将被自动假定为函数。这已经从C标准中删除了。