为什么strcpy()不包含<;字符串.h>;

为什么strcpy()不包含<;字符串.h>;,c,gcc,C,Gcc,我正在使用一些C示例,并使用函数strcpy(),但是忘记了包含,尽管我已经包含了。令我惊讶的是,代码成功运行。以下是我正在执行的代码: #include <stdio.h> int main() { char message[10]; int count, i; strcpy(message, "Hello, world!"); printf("Repeat how many times? "); scanf("%d", &count);

我正在使用一些C示例,并使用函数
strcpy()
,但是忘记了包含
,尽管我已经包含了
。令我惊讶的是,代码成功运行。以下是我正在执行的代码:

#include <stdio.h>

int main() {
   char message[10];
   int count, i;

   strcpy(message, "Hello, world!");

   printf("Repeat how many times? ");
   scanf("%d", &count);

   for(i=0; i < count; i++) {
      printf("%3d - %s\n", i, message);
   }
}
#包括
int main(){
字符消息[10];
int计数,i;
strcpy(信息“你好,世界!”);
printf(“重复多少次?”);
scanf(“%d”、&count);
对于(i=0;i
我使用的是gcc版本3.3.6(Ubuntu 1:3.3.6-15ubuntu1)

我甚至没有收到任何编译警告

为什么我的代码没有包含


提前感谢。

编译器假定
int strcpy()
并调用古老的向后兼容性行为。指针参数是这种方法适用的类型之一,因此它很好

别指望它。安全轨道已关闭。

编译器知道一些“内置”函数(
printf()
是一些编译器的另一个示例),并通过提供它来弥补您的错误。依赖它是一个坏习惯,因为即使今天的编译器这样做,也不能保证另一个编译器也会这样做,因此编译后的代码是不可预测的

尝试使用
-Wall-Wextra
编译,使编译器显示更多警告,包括您忘记的标题:
gcc-o input input.c-Wall-Wextra


另请参见此处:

我记得,GCC 3默认为C89一致性加上GNU扩展。C89允许调用之前未声明的函数——假定它们返回
int
,并从参数类型推断出它们的参数类型。如果生成的隐式类型恰好与被调用函数的实际类型相匹配(这在旧式C代码中比在现代代码中更可能),那么一切都是好的。如果没有,那么行为是未定义的,但是任何未定义的行为都可能发生,甚至是编写代码的程序员期望发生的事情

此外,尽管这些标准没有指定任何标准头包含其他头,但它们并没有被禁止这样做,在实践中,在一些C实现中,其中一些是这样做的。如果您的实现的
stdio.h
包含
string.h
或以其他方式为
strcpy()
提供了兼容的定义,那么该实现就很好了。然而,如果这正是您所依赖的,无论是有意还是无意,那么当您尝试使用不同实现的程序时,您将面临意外失败的风险


最后,请注意GCC 3.3非常古老。如果可能的话,您应该升级到更新的版本。即使是单调、长期稳定的Linuxes也倾向于至少使用4.x系列的最新版本,最新版本是GCC 8.3。
string.h
include文件告诉编译器如何通过给出函数声明来定义
strcpy()
,但它不提供函数本身,相反,它位于库中,并将自动与您的程序链接

如果函数到达时还没有声明,那么编译器将根据默认值和使用函数的方式进行声明

编译器接受您编写的内容,因此
消息
你好,世界
并假定函数返回
int
。由于
include
,如果不告诉编译器它必须如何编译代码,您就要冒风险。结果是未定义的行为

顺便说一下,
你好,世界包含14个字符,13+尾随的
\0
,比您声明的
消息
多4个字符。这是未定义的行为,因为额外的4个字符将写在不应该写的地方。似乎在工作,崩溃

您不能依赖显示预期结果的程序。这是未定义的行为


总是用警告选项编译,如代码>墙>代码,并考虑修复所有警告。

这是如何与未定义的行为一起进行的。您不会总是这么幸运,编译器警告应该认真对待。@AbhayKumar尝试使用
-Wall-Wextra
启用警告。是否确定行为未定义,@WeatherVane?如果实现的
stdio.h
包含
string.h
(看似合理,但不能保证)会怎么样?我们将旋钮调到11。C4013:“strcpy”未定义;假设外部程序返回int.
strcpy(消息“你好,世界!”)这是一个明确的缓冲区溢出,这是关于声明和实现之间区别的一个很好的观点,并且经常被新手误解(+1)。然而,您的措辞可能会导致混淆,因为如果标题确实包含
strcpy()
的定义,那么它将提供该函数。它包含一个声明,告诉编译器函数是如何定义的。在这种情况下,我希望您不要反对进一步的调整(编辑)。GCC 5.1(2015年4月)是第一个默认为C11的版本;没有默认为C99的版本。GCC3非常非常古老(2006年3月3.4.6日是最后一个3.x版本;2005年5月3.3.6日;2004年5月3.3日)。信息来自。