问题描述
这很容易推理怎么这么code将工作:
It's easy to reason how such a code would work:
#include <string.h>
#define strcmp my_strcmp
int my_strcmp(const char *, const char *)
...
strcmp(str1, str2);
...
但这个问题是这是否在技术上是正确与否。
But this question is whether this is technically correct or not.
从C11:
7.1.3.1(对保留名称):
7.1.3.1 (on reserved names):
...
- 在以下任一小节的每个宏名称(包括未来图书馆
方向)被保留用于如果任何相关标头包括按照指定;
除非另有明确规定(见7.1.4)。 - 在以下任一小节的外部连接(包括所有的标识符
未来图书馆方向)和错误号总是保留用作使用标识符
外部链接。) - 在任一下列条款上市文件范围内每个标识符(包括
未来图书馆方向)被保留用于为宏名称和与标识符
如果任何相关头包括文件相同的命名空间范围。
保留标识符有外部链接的列表包括math_errhandling,setjmp的,va_copy,va_end用来
The list of reserved identifiers with external linkage includes math_errhandling, setjmp, va_copy, and va_end.
因此,这意味着 STRCMP
是一个保留字,因为文件string.h
包含
So this means that strcmp
is a reserved word because string.h
is included.
7.1.3.2:
...如果程序声明或定义(除7.1.4所允许除外),或保留标识符定义为宏名在上下文中的标识符,它被保留,其行为是不确定的。
现在这似乎是说重新定义 STRCMP
是不确定的行为,但它在某种程度上7.1.4允许的。
Now this seems to say redefining strcmp
is undefined behavior, except it is somehow allowed in 7.1.4.
7.1.4的可能相关的内容是:
The possibly relevant contents of 7.1.4 are:
7.1.4.1:
...在头声明的任何功能可另外实施为在头中定义的函数宏,因此,如果一个库函数被声明明确当包括其头,可以使用如下所示的技术之一以确保声明不受这样的宏。一个功能的任何宏定义可以是由包围在括号中的功能的名称局部pssed SUP $ P $,因名然后后面没有左括号,指示宏函数名的扩展。出于同样的句法原因,它允许采取即使它也被定义为一个宏库函数的地址。)使用和#undef的,以消除任何宏定义也将确保实际的功能被提及。 ...
这意味着,一个实现应为每个库函数的实际功能,即使它也提供了该功能的宏。
This means that an implementation shall provide an actual function for each library function, even if it also provides a macro for that function.
7.1.4.2:
但库函数可以不参考在头中定义的任何类型进行声明,它也允许声明函数并使用它而不包括其
相关的头。
条款的其余部分是不相关的。我看不出有什么7.1.3.2称之为所允许的7.1.4,除了在相同的标题作为函数库函数的的定义,即标准头的作为宏。
The rest of the clauses are irrelevant. I don't see what 7.1.3.2 refers to as "as allowed by 7.1.4", except the definition of the library function in the same header as the function, i.e. the standard header, as a macro.
在总结,是code以上techincally未定义行为?怎么样,如果文件string.h
没有被列入?
In summary, is the code above techincally undefined behavior? How about if string.h
was not included?
推荐答案
至少有一个原因,它的UB是文件string.h
可以引入宏。对于内部实现的原因,这些宏可能已经写在假设 STRCMP
是真实的strcmp功能。如果定义 STRCMP
是别的东西,然后用这些宏, STRCMP
将扩大到 my_strcmp
中的宏,意想不到的后果。
At least one reason why it's UB is that string.h
can introduce macros. For internal implementation reasons, those macros might have been written on the assumption that strcmp
is the "real" strcmp function. If you define strcmp
to be something else and then use those macros, strcmp
will expand to my_strcmp
in the macros, with unexpected consequences.
而不是试图找出到底是什么code将是确定的 ...
,什么也不会,标准提出早日站到你的诡计
Rather than try to work out exactly what code would be OK in the ...
and what would not, the standard puts an early stop to your shenanigans.
另外要注意的是,除了从标准的单位出禁止它,你的的#define STRCMP my_strcmp
可能是一个宏重新定义,其实是因为文件string.h
被允许做的#define STRCMP __strcmp
或什么的。因此,对一些符合实现中形成不良的code。
Also note that aside from the fact that the standard flat-out forbids it, your #define strcmp my_strcmp
might be a macro re-definition, because string.h
is permitted to do #define strcmp __strcmp
or whatever. So on some conforming implementations your code is ill-formed.
这篇关于它是不确定的行为重新定义一个标准的名字吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!