很容易推断这样的代码是如何工作的:
#include <string.h>
#define strcmp my_strcmp
int my_strcmp(const char *, const char *)
...
strcmp(str1, str2);
...
但这个问题是这在技术上是否正确。
从 C11:
7.1.3.1(关于保留名称):
...
- 如果包含任何关联的头文件,则以下任何子条款(包括未来的库方向)中的每个宏名称都保留用于指定使用;除非另有明确说明(见 7.1.4)。
- 以下任何子条款(包括未来的库方向)和 errno 中的所有具有外部链接的标识符始终保留用作具有外部链接的标识符。184 )
- 如果包含任何关联的标头,则保留在以下任何子条款(包括未来的库方向)中列出的具有文件范围的每个标识符用作宏名称和具有相同名称空间中的文件范围的标识符。
184具有外部链接的保留标识符列表包括 math_errhandling、setjmp、va_copy 和 va_end。
所以这意味着这strcmp
是一个保留字,因为string.h
被包含在内。
7.1.3.2:
...如果程序在保留标识符的上下文中声明或定义标识符(7.1.4 允许的除外),或将保留标识符定义为宏名称,则行为未定义。
现在这似乎说重新定义strcmp
是未定义的行为,除非它在 7.1.4 中以某种方式被允许。
7.1.4可能相关的内容有:
7.1.4.1:
...在头文件中声明的任何函数都可以另外实现为头文件中定义的类似函数的宏,因此如果在包含头文件时显式声明库函数,则可以使用下面显示的技术之一来确保声明不受此类宏的影响。函数的任何宏定义都可以通过将函数的名称括在括号中来在本地抑制,因为该名称后面没有表示宏函数名称扩展的左括号。出于同样的语法原因,即使库函数也被定义为宏,也允许获取库函数的地址。185 ) 使用#undef 删除任何宏定义也将确保引用实际函数。...
185这意味着实现应为每个库函数提供一个实际函数,即使它还为该函数提供了一个宏。
7.1.4.2:
如果可以在不引用头文件中定义的任何类型的情况下声明库函数,则也允许声明函数并在不包括其关联头文件的情况下使用它。
其余条款无关紧要。我看不到 7.1.3.2 所指的“7.1.4 所允许的”,除了库函数在与函数相同的头文件中的定义,即标准头文件,作为宏。
总之,上面的代码在技术上是未定义的行为吗?如果string.h
不包括怎么办?