[英]Why does C language allow users to create Macros whose name are the same as a pre-existing library function?
# include <stdio.h>
# define scanf "%s Hello World"
int main (void)
{
printf(scanf, scanf);
getchar();
return 0;
}
In the above code snippet, before the code is executed, the macro expansion phase takes place.在上面的代码片段中,在代码执行之前,发生了宏扩展阶段。 In this, each occurrence of 'scanf' is replaced by
"%s Hello World"
.在此,每次出现的 'scanf' 都被替换为
"%s Hello World"
。
Hence printf(scanf,scanf)
will become printf(“%s Hello World”, “%s Hello World”)
.因此
printf(scanf,scanf)
将变为printf(“%s Hello World”, “%s Hello World”)
。
The final output will be:最终的 output 将是:
%s Hello World Hello World
Now, no problems were encountered in this program because we did not use the scanf function here.现在,这个程序没有遇到任何问题,因为我们在这里没有使用scanf function。
However, if we use the scanf function for some purpose但是,如果我们出于某种目的使用 scanf function
# include <stdio.h>
# define scanf "%s Hello World"
int main(void)
{
int x;
printf(scanf, scanf);
scanf("%d",&x);
getchar();
return 0;
}
We encounter an error:我们遇到一个错误:
main.c: In function ‘main’:
main.c:2:17: error: called object is not a function or function pointer
# define scanf "%s Hello World"
^
main.c:7:4: note: in expansion of macro ‘scanf’
scanf("%d",&x);
^~~~~
Why does then C allow us to name macros after library functions like Scanf in the first place?那么为什么 C 首先允许我们以 Scanf 之类的库函数命名宏?
C 2018 7.1.3 1 says: C 2018 7.1.3 1 说:
… Each identifier with file scope listed in any of the following subclauses (including the future library directions) is reserved for use as a macro name and as an identifier with file scope in the same name space if any of its associated headers is included.
…在以下任何子条款(包括未来的库方向)中列出的文件 scope 的每个标识符(包括未来的库方向)都保留用作宏名称,并且如果包含任何关联的标头,则作为文件 scope 的标识符在同一名称空间中使用。
scanf
is an identifier with file scope listed in a following subclause (7.21), and you include its header, , so it is reserved for use as a macro name. scanf
是带有文件 scope 的标识符,列在以下子条款 (7.21) 中,并且包含其 header, ,因此保留用作宏名称。
7.1.3 2 says: 7.1.3 2 说:
… If the program declares or defines an identifier in a context in which it is reserved (other than as allowed by 7.1.4), or defines a reserved identifier as a macro name, the behavior is undefined.
... 如果程序在保留标识符的上下文中声明或定义标识符(7.1.4 允许的除外),或将保留标识符定义为宏名称,则行为未定义。
Combined, these rules say that, if you define scanf
as a macro name and include <stdio.h>
, the C standard does not impose any requirements on what happens—it is not specified to be an error in your program, nor is the compiler required to reject your program as incorrect.结合起来,这些规则表明,如果您将
scanf
定义为宏名称并包含<stdio.h>
,则 C 标准不会对发生的情况施加任何要求——它没有被指定为您的程序中的错误,也不是编译器需要将您的程序视为不正确而拒绝。 The compiler is also not required not to reject your program.编译器也不需要拒绝您的程序。
There is an alternative which avoids this problem: You can omit #include <stdio.h>
and instead declare printf
(and any other functions from <stdio.h>
that you use) yourself.有一种替代方法可以避免此问题:您可以省略
#include <stdio.h>
而是自己声明printf
(以及您使用的<stdio.h>
中的任何其他函数)。 The C standard explicits allows this, and then you can freely define a macro for scanf
. C 标准明确允许这样做,然后您可以为
scanf
自由定义宏。
This is typical of much of the C standard: It does not prevent you from doing things that can cause problems.这是 C 标准的典型特征:它不会阻止您做可能导致问题的事情。 In particular, it does not require the compiler warn you about it.
特别是,它不需要编译器警告您。 There are at least three reasons (good or bad) the C standard is designed this way:
至少有三个原因(好或坏)C 标准是这样设计的:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.