繁体   English   中英

为什么声明的原型的函数类型不需要与实际函数的类型匹配?

[英]Why does a declared prototype's function type not need to match the actual function's type?

我有一个使用功能function_1的file1。 在使用file1编译的file2中,我将该函数定义为int function_1(char a) 在我的file1中,我有原型行void function_1(char a) 当我进行编译和测试时,一切正常,并且没有任何警告。 为什么这样可以? 为什么无论哪种方式都要求原型函数类型?

编辑:我很感谢警告,但只有默波芬尝试回答所提出的问题,尽管我对回答不满意。 如果链接器不检查类型,为什么它甚至根本不应该成为声明的一部分?

这是因为编译器会针对给定的单个文件进行所有检查,并且编译结果仅包含对名称function_1的引用。 链接器不检查任何类型,它仅连接名称。

C使用类型有两个目的:

  1. 用于一致性检查(以防止程序员犯(一些)明显的错误)
  2. 对于代码生成(类型告诉编译器要为变量保留多少内存,生成哪些代码来访问它们,等等)

所有这些一次完成一个编译单元。 (编译单元基本上是一个.c文件,其中包括所有标头。)

您可以在不同的编译单元中声明不同类型的相同名称。 (因为编译器一次只考虑一个单元,所以不会捕获该单元。)

但这意味着您有两段代码,对程序要处理的实体类型有不同的想法。 这会在运行时导致有趣和令人兴奋的错误。 具体细节取决于您的平台/ ABI。

例如,在x86上, floatint具有相同的大小(4个字节)。 您可以定义一个功能

float foo(void) { return 42.0f; }

在文件A中并声明为

int foo(void);

您可能希望生成的程序可以正常运行,只是它将重新解释42.0f的位模式为整数。 但这不是发生的情况:调用约定指定%eax寄存器中返回int ,而float使用%st0浮点寄存器。 可能的结果是,A将把42.0f放在%st0而B将采用%eax中的任何值作为foo的返回值。

(这可能会以更有趣的方式出错:例如float bar[] = { ... };在一个文件中可以使用float bar[] = { ... };在另一个文件中可以使用void bar(void);在另一个文件中。这可能会导致第二个文件解释内容浮点数组作为机器代码(在调用bar()时执行)。

这就是为什么编译器需要知道参数的类型和返回值的原因:因此,它可以为函数调用生成正确的代码(将参数放在函数期望的位置,并从函数放入的位置获取返回值) 。

但是不幸的是,它不会交叉检查多个文件中的声明,而是依靠程序员来正确地执行它。 这就是为什么最佳实践是在标头文件中声明“导出的”(或“公共”)函数(即未标记为static函数),该标头文件同时包含在定义函数的文件和这些函数的用户中。 这样,您无需手动声明要调用的函数,并且无论如何都要进行声明,任何类型的不匹配都将被视为无效/不兼容的重新声明。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM