英文:
Why does gcc need the definition of unused _Generic values?
问题
以下是翻译好的部分:
这段代码不会在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>
,问题是为什么要这样做。
英文:
Consider this code:
#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;
}
It will not compile with gcc nor clang (don't know about other compilers), gcc complains with error: ‘FLT_MAX’ undeclared (first use in this function) ...
(even without any warning flags) But why? i use the GETMAX
with a integer, the value of FLT_MAX
is irrelevant for that, on my machine, only UCHAR_MAX
should be needed. The line if( argc>GETMAX(a) )
should turn into a equivalent of if( argc>UCHAR_MAX )
(after compiling, FLT_MAX
is still there after the preprocessor), making all other limits irrelevant.
The fix is easy, just add #include <float.h>
, the question is about why this is the way it is.
答案1
得分: 3
C语言要求所有在表达式中使用的标识符都必须声明。1 虽然可能重新设计语言以忽略某些地方的未声明标识符,但要求声明有助于避免错误。
还有其他情况下,未知的标识符可能会被忽略。例如,请考虑以下代码:
int foo(void)
{
return 1 || x;
}
1 || x
的值无论 x
有什么值都是1。然而,如果在此之前代码中有 typedef int x;
,那么会报错,因为||
的右操作数必须是一个语法上的逻辑与表达式,而类型不是一个表达式。因此,在 x
未声明的情况下,编译器无法检查 1 || x
是否符合C标准规定的有效表达式的规则。
另一个例子是 int a[3]; return sizeof a[x];
,如果被接受,将返回一个int
的大小,而不管 x
是什么值。在这种情况下,C标准规定 x
不会被评估。然而,它必须被声明。另一个例子是 return 0; x;
。在这里,程序控制永远不会到达 x
,因此它永远不会被评估。但是它必须被声明。
类似地,在 _Generic
中,:
后面的语法实体必须是一个赋值表达式,除非其中的标识符已被声明,否则编译器无法检查这一点。
脚注
1 在过去,作为函数调用中的函数指示符使用的标识符会被自动假定为函数。这已从C标准中删除。
英文:
C expects all identifiers used in expressions to be declared.<sup>1</sup> While it might be possible to redesign the language to ignore undeclared identifiers in certain places, requiring declarations helps avoid bugs.
There are other places where an unknown identifier might be ignored. For example, consider:
int foo(void)
{
return 1 || x;
}
The value of 1 || x
is 1 regardless of what value x
has. However, if typedef int x;
were in the code before this, it would be an error, because the right operand of ||
must be a grammatical logical-AND-expression, and a type is not an expression. So, with x
undeclared, the compiler cannot check whether 1 || x
is a valid expression as defined by the rules of the C standard.
Another example is int a[3]; return sizeof a[x];
, which would, if accepted, return the size of an int
regardless of x
. In this, the C standard says x
is not evaluated. Yet it must be declared. Another example is return 0; x;
. Here, there is no way for program control to reach x
, so it is never evaluated. Yet it must be declared.
Similarly, in _Generic
, the grammatical entity after a :
must be an assignment-expression, and the compiler cannot check that unless the identifiers in it are declared.
Footnote
<sup>1</sup> In the past, an identifier used as a function designator in a call would be automatically assumed to be a function. This has been removed from the C standard.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论