繁体   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; 
}

在上面的代码片段中,在代码执行之前,发生了宏扩展阶段。 在此,每次出现的 'scanf' 都被替换为"%s Hello World"

因此printf(scanf,scanf)将变为printf(“%s Hello World”, “%s Hello World”)

最终的 output 将是:

%s Hello World Hello World

现在,这个程序没有遇到任何问题,因为我们在这里没有使用scanf function。

但是,如果我们出于某种目的使用 scanf function

# include <stdio.h> 
# define scanf  "%s Hello World" 
int main(void) 
{ 
   int x;
   printf(scanf, scanf); 
   scanf("%d",&x);
   getchar(); 
   return 0; 

}

我们遇到一个错误:

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);
    ^~~~~

那么为什么 C 首先允许我们以 Scanf 之类的库函数命名宏?

C 2018 7.1.3 1 说:

…在以下任何子条款(包括未来的库方向)中列出的文件 scope 的每个标识符(包括未来的库方向)都保留用作宏名称,并且如果包含任何关联的标头,则作为文件 scope 的标识符在同一名称空间中使用。

scanf是带有文件 scope 的标识符,列在以下子条款 (7.21) 中,并且包含其 header, ,因此保留用作宏名称。

7.1.3 2 说:

... 如果程序在保留标识符的上下文中声明或定义标识符(7.1.4 允许的除外),或将保留标识符定义为宏名称,则行为未定义。

结合起来,这些规则表明,如果您将scanf定义为宏名称并包含<stdio.h> ,则 C 标准不会对发生的情况施加任何要求——它没有被指定为您的程序中的错误,也不是编译器需要将您的程序视为不正确而拒绝。 编译器也不需要拒绝您的程序。

有一种替代方法可以避免此问题:您可以省略#include <stdio.h>而是自己声明printf (以及您使用的<stdio.h>中的任何其他函数)。 C 标准明确允许这样做,然后您可以为scanf自由定义宏。

这是 C 标准的典型特征:它不会阻止您做可能导致问题的事情。 特别是,它不需要编译器警告您。 至少有三个原因(好或坏)C 标准是这样设计的:

  • 它允许灵活性和扩展性。 C 被设计为一种可移植语言,并不是说程序在任何地方都以相同的方式工作,而是因为 C 可以相对容易地为各种计算平台实现。 C 标准具有灵活性,因此可以根据平台调整语言,并允许实现提供超出标准规定的语言扩展。
  • 它减少了编译器的工作量。 通过不对编译器施加太多要求,它使编写它们变得更容易。 (然后,是否对程序实施额外检查成为质量问题,而不是遵守 C 标准。这项政策运作良好。即使没有标准的要求,今天广泛使用的编译器也比几十年前的编译器质量要高得多.)
  • 它允许在 C 标准发布之前编写的一些代码继续使用该标准。 在有关于使用库函数作为宏名称的规则之前,可能已经编写了一些这样做的程序(程序员可能会这样做,因为他们想在某种程度上改变库 function,至少在外观上)。 要求编译器拒绝这些程序将需要做一些工作以使这些程序与新的语言标准一起工作。

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM