据说我们可以编写多个声明但只能编写一个定义.现在,如果我使用相同的原型实现我自己的strcpy函数:
char * strcpy ( char * destination, const char * source );
Run Code Online (Sandbox Code Playgroud)
那么我不是在重新定义现有的库函数吗?这不应该显示错误吗?或者它是否以某种方式与库函数以目标代码形式提供的事实有关?
编辑:在我的机器上运行以下代码说"分段故障(核心转储)".我正在使用linux并且已经编译而没有使用任何标志.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *strcpy(char *destination, const char *source);
int main(){
char *s = strcpy("a", "b");
printf("\nThe function ran successfully\n");
return 0;
}
char *strcpy(char *destination, const char *source){
printf("in duplicate function strcpy");
return "a";
}
Run Code Online (Sandbox Code Playgroud)
请注意,我不是要尝试实现该功能.我只是想重新定义一个函数并询问后果.
编辑2:在应用Mats建议的更改后,程序不再提供分段错误,尽管我仍在重新定义函数.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *strcpy(char *destination, const char *source);
int main(){
char *s = strcpy("a", "b");
printf("\nThe function ran successfully\n");
return 0;
}
char *strcpy(char *destination, const char *source){
printf("in duplicate function strcpy");
return "a";
}
Run Code Online (Sandbox Code Playgroud)
Yu *_*Hao 11
C11(ISO/IEC 9899:201x)§7.1.3 保留标识符
- 如果包含任何相关标头,则保留以下任何子条款中的每个宏名称(包括未来的库方向)以供指定使用; 除非另有明确说明.
- 以下任何子条款中包含外部链接的所有标识符(包括未来的库方向)始终保留用作具有外部链接的标识符.
- 如果包含任何相关标头,则保留下列任何子条款(包括未来库方向)中列出的具有文件范围的每个标识符,以用作宏名称和具有相同名称空间的文件范围的标识符.
如果程序在保留它的上下文中声明或定义标识符,或者将保留标识符定义为宏名称,则行为是未定义的.请注意,这并不意味着你不能这样做,正如这篇文章所示,它可以在gcc和glibc中完成.
glibc的§1.3.3保留名称 proveds更清晰的理由:
来自ISO C标准的所有库类型,宏,变量和函数的名称都是无条件保留的; 您的程序可能不会重新定义这些名称.如果您的程序明确包含定义或声明它们的头文件,则保留所有其他库名.这些限制有几个原因:
如果您使用名为exit的函数执行与标准退出函数完全不同的操作,那么阅读代码的其他人可能会非常困惑.防止这种情况有助于使您的程序更易于理解,并有助于模块化和可维护性.
它避免了用户意外重新定义其他库函数调用的库函数的可能性.如果允许重新定义,那些其他功能将无法正常工作.
它允许编译器在调用这些函数时进行任何特殊的优化,而不会被用户重新定义.一些库设施,例如用于处理可变参数(参见Variadic函数)和非本地出口(参见非本地退出)的设施,实际上需要C编译器方面的大量合作,并且相对于实现,编译器可能更容易将它们视为语言的内置部分.
这几乎肯定是因为你传递的是一个"字符串文字"的目的地.
char*s = strcpy("a","b");
随着编译器知道"我可以做strcpy内联",所以你的函数永远不会被调用.
您正试图复制"b"字符串文字"a",这将无法正常工作.
创建一个char a[2];并且strcpy(a, "b");它将运行 - 它可能不会调用您的strcpy函数,因为strcpy即使您没有可用的优化,编译器也会内联.