简体   繁体   English

为什么C语言允许用户创建与已有库function同名的宏?

[英]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 标准是这样设计的:

  • It allows flexibility and extensions.它允许灵活性和扩展性。 C was designed to be a portable language, not in the sense that a program works in the same way everywhere but in the sense that C can be implemented for a variety of computing platforms with relative ease. C 被设计为一种可移植语言,并不是说程序在任何地方都以相同的方式工作,而是因为 C 可以相对容易地为各种计算平台实现。 The C standard allows flexibility so the language can be adjusted to a platform, and it allows implementations to provide extensions to the language beyond what the standard specifies. C 标准具有灵活性,因此可以根据平台调整语言,并允许实现提供超出标准规定的语言扩展。
  • It reduces the work load on compilers.它减少了编译器的工作量。 By not imposing many requirements on compilers, it makes it easier to write them.通过不对编译器施加太多要求,它使编写它们变得更容易。 (Then, whether to implement extra checks on programs becomes a matter of quality rather than of adherence to the C standard. This policy has worked well. Even without requirements from the standadr, today's widely available compilers are much higher quality than those of decades ago.) (然后,是否对程序实施额外检查成为质量问题,而不是遵守 C 标准。这项政策运作良好。即使没有标准的要求,今天广泛使用的编译器也比几十年前的编译器质量要高得多.)
  • It allowed some code written before the C standard was published to continue working with the standard.它允许在 C 标准发布之前编写的一些代码继续使用该标准。 Before there were rules about using library functions as macro names, some programs may have been written that did so (which programmers might do because they wanted to somewhat alter the library function, at least in appearance).在有关于使用库函数作为宏名称的规则之前,可能已经编写了一些这样做的程序(程序员可能会这样做,因为他们想在某种程度上改变库 function,至少在外观上)。 Requiring compilers to reject those programs would require work to be done to get those programs working with the new language standard.要求编译器拒绝这些程序将需要做一些工作以使这些程序与新的语言标准一起工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何调用名称与c中的局部变量名称相同的函数 - how to call a function whose name is the same of the local variable name in c 使库具有多个类,其他预先存在的.a库和其他依赖项 - Making library with multiple classes, additional pre-existing .a library and other dependencies 开始预先存在的项目 - Starting work on a Pre-existing Project 是否可以使用预先存在的函数或代码来计算POSIX程序中的TCP段校验和 - Is there a pre-existing function or code I can use to compute a TCP segment checksum in a POSIX program 为什么这段代码有效? function 的输入是“string s”,但我们给出的实际输入是“int name”。 C语言 - Why does this code work? The input for the function is "string s" but the actual input we are giving is "int name". C language C语言巨集 - Macros in C language 用 C 宏替换部分函数/变量名 - Replace part of a function/variable name with C macros C语言中的宏(#define) - A macros in the C language (#define) 如何获取g_dbus_connection_signal_subscribe函数来告诉我有关预先存在的对象/接口的信息? - How can I get the g_dbus_connection_signal_subscribe function to tell me about pre-existing objects/interfaces? 为什么/ C允许隐式函数和无类型变量声明? - Why does/did C allow implicit function and typeless variable declarations?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM