为什么strcpy()在不包含<string.h>的情况下工作

时间:2019-04-02 14:19:22

标签: c gcc

我正在使用某些C示例,并使用函数strcpy(),但是尽管我包含了<string.h>,但是却忘记了包含<stdio.h>。令我惊讶的是,代码成功运行了。以下是我正在执行的代码:

#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);
   }
}

我正在使用gcc version 3.3.6 (Ubuntu 1:3.3.6 - 15ubuntu1)

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

enter image description here

为什么我的代码在不包含<string.h>的情况下工作?

谢谢。

4 个答案:

答案 0 :(得分:3)

编译器假定int strcpy()并调用古老的向后兼容行为。指针参数是可以使用的一种类型,所以很好。

不要依赖它。安全导轨已关闭。

答案 1 :(得分:3)

我记得,GCC 3默认为C89一致性以及GNU扩展。 C89允许在不事先声明的情况下调用函数-假定它们返回int,并且从参数类型推断出它们的参数类型。如果结果隐式类型恰好与被调用函数的实际类型相匹配(在旧版C代码中比在现代代码中更有可能),那么一切都很好。如果不是这样,则该行为是不确定的,但任何不确定的行为都可能发生,甚至是编写代码的程序员所期望发生的一切。

此外,尽管标准未指定任何标准标头包含其他标头,但也不禁止这样做,实际上,在某些C实现中,其中一些标头也可以。如果您的实现的stdio.h包含string.h或以其他方式提供了strcpy()的兼容定义,那么对于该实现就可以了。但是,如果这是您所依赖的,则无论有意还是无意,当您尝试将程序与其他实现一起使用时,都可能会出现意外失败的风险。

最后,请注意,GCC 3.3的版本非常。如果有可能,您应该升级到较新的版本。甚至那些长期稳定的Linux也倾向于至少在4.x系列中使用最新版本,而最新版本是GCC 8.3。

答案 2 :(得分:2)

string.h包含文件告诉编译器如何 strcpy()是通过给出函数的声明来定义的,但它并不提供函数本身,而是位于在库中,并会自动与您的程序链接。

如果尚未在到达函数时声明该函数,则编译器将根据默认值和您如何使用该函数假定一个声明。

编译器接受您编写的内容,因此messageHello, world!的地址并假定函数返回int。由于include,您不必告诉编译器如何编译代码,从而冒了风险。结果是不确定的行为。

顺便说一句,Hello, world!包含14个字符,13个+尾随的\0,比您声明的message多4个字符。这是未定义的行为,因为多余的4个字符将被写在不应包含的位置。似乎正在工作,崩溃...

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

始终使用-Wall之类的警告选项进行编译,并考虑修复所有警告。

答案 3 :(得分:0)

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

尝试使用-Wall -Wextra进行编译,以使编译器显示更多警告,包括有关您已忘记的标头的警告:gcc -o input input.c -Wall -Wextra

也请参见此处:warning: incompatible implicit declaration of built-in function ‘xyz’