为什么gcc需要定义unused _Generic值?

46qrfjad  于 2023-06-23  发布在  其他
关注(0)|答案(1)|浏览(101)

考虑以下代码:

#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>,问题是为什么会这样。

quhf5bfb

quhf5bfb1#

C期望表达式中使用的所有标识符都被声明。1虽然可能重新设计语言以忽略某些地方未声明的标识符,但要求声明有助于避免错误。
还有一些地方可能会忽略未知的标识符。例如,考虑:

int foo(void)
{
    return 1 || x;
}

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标准中删除了。

相关问题