简体   繁体   English

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

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

I have a file1 that uses the function function_1 . 我有一个使用功能function_1的file1。 In a file2 that I compile with file1, I defined the function as int function_1(char a) . 在使用file1编译的file2中,我将该函数定义为int function_1(char a) In my file1, I have the prototype line void function_1(char a) . 在我的file1中,我有原型行void function_1(char a) When I compile and test, everything works fine and I don't have any warnings. 当我进行编译和测试时,一切正常,并且没有任何警告。 Why is this ok? 为什么这样可以? Why even ask for the prototype function type if it works either way? 为什么无论哪种方式都要求原型函数类型?

edit: I appreciate the warnings, but only melpomene has even made an attempt to answer the question that was asked, although I am not satisfied with the answer. 编辑:我很感谢警告,但只有默波芬尝试回答所提出的问题,尽管我对回答不满意。 If the linker doesn't check types, why should it even be part of the declaration at all? 如果链接器不检查类型,为什么它甚至根本不应该成为声明的一部分?

It's because the compiler does all checks for the single file it's been given, and the compilation result just contains a reference to the name function_1 . 这是因为编译器会针对给定的单个文件进行所有检查,并且编译结果仅包含对名称function_1的引用。 The linker doesn't check any types, it just connects names. 链接器不检查任何类型,它仅连接名称。

C uses types for two purposes: C使用类型有两个目的:

  1. For consistency checks (to prevent (some) obvious mistakes by the programmer) 用于一致性检查(以防止程序员犯(一些)明显的错误)
  2. For code generation (the types tell the compiler how much memory to reserve for variables, what code to generate to access them, etc.) 对于代码生成(类型告诉编译器要为变量保留多少内存,生成哪些代码来访问它们,等等)

All of this is done one compilation unit at a time. 所有这些一次完成一个编译单元。 (A compilation unit is basically a .c file and all the headers it includes.) (编译单元基本上是一个.c文件,其中包括所有标头。)

You can declare the same name with different types in different compilation units. 您可以在不同的编译单元中声明不同类型的相同名称。 (Because the compiler only considers one unit at a time, it won't catch this.) (因为编译器一次只考虑一个单元,所以不会捕获该单元。)

But that means you have two pieces of code with different ideas about what kind of entity the program is dealing with. 但这意味着您有两段代码,对程序要处理的实体类型有不同的想法。 This can lead to fun and exciting bugs at runtime. 这会在运行时导致有趣和令人兴奋的错误。 The exact details depend on your platform/ABI. 具体细节取决于您的平台/ ABI。

For example, on x86 a float and an int have the same size (4 bytes). 例如,在x86上, floatint具有相同的大小(4个字节)。 You can define a function 您可以定义一个功能

float foo(void) { return 42.0f; }

in file A and declare it as 在文件A中并声明为

int foo(void);

in file B. You might expect the resulting program to mostly work, except it would reinterpret the bit pattern for 42.0f as an integer. 您可能希望生成的程序可以正常运行,只是它将重新解释42.0f的位模式为整数。 But that's not what happens: The calling convention specifies that an int is returned in the %eax register whereas a float uses the %st0 floating-point register. 但这不是发生的情况:调用约定指定%eax寄存器中返回int ,而float使用%st0浮点寄存器。 The likely result is that A will put 42.0f in %st0 but B will take whatever happens to be in %eax as the return value of foo . 可能的结果是,A将把42.0f放在%st0而B将采用%eax中的任何值作为foo的返回值。

(This can go wrong in more interesting ways: You could have eg float bar[] = { ... }; in one file and void bar(void); in the other. This will probably result in the second file interpreting the contents of the floating-point array as machine code (to be executed when calling bar() ).) (这可能会以更有趣的方式出错:例如float bar[] = { ... };在一个文件中可以使用float bar[] = { ... };在另一个文件中可以使用void bar(void);在另一个文件中。这可能会导致第二个文件解释内容浮点数组作为机器代码(在调用bar()时执行)。

This is why the compiler needs to know the types of the parameters and return value: It's so it can generate the right code for a function call (putting arguments where the function expects them, and retrieving the return value from where the function put it). 这就是为什么编译器需要知道参数的类型和返回值的原因:因此,它可以为函数调用生成正确的代码(将参数放在函数期望的位置,并从函数放入的位置获取返回值) 。

But unfortunately it doesn't cross-check declarations in multiple files, relying on the programmer to get it right. 但是不幸的是,它不会交叉检查多个文件中的声明,而是依靠程序员来正确地执行它。 That's why it is best practice to declare your "exported" (or "public") functions (ie those don't marked as static ) in a header file that is included both by the file that defines the functions and by users of those functions. 这就是为什么最佳实践是在标头文件中声明“导出的”(或“公共”)函数(即未标记为static函数),该标头文件同时包含在定义函数的文件和这些函数的用户中。 This way you don't need to manually declare functions you want to call, and if you do it anyway, any type mismatches will be caught as an invalid/incompatible redeclaration. 这样,您无需手动声明要调用的函数,并且无论如何都要进行声明,任何类型的不匹配都将被视为无效/不兼容的重新声明。

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

相关问题 为什么函数需要在定义或使用之前声明? - Why does a function need to be declared before it's defined or used? 为什么返回 int 的 function 不需要原型? - Why does a function that returns int not need a prototype? 为什么函数返回类型需要为C中的线程类型(void *)? - Why does function return type need to be of type (void*) for threading in C? 为什么在一个函数中声明的union类型在另一个函数中使用它无效? - Why is it invalid for a union type declared in one function to be used in another function? 函数定义与原型冲突类型 - function definition conflicting type with prototype 如果内联函数使用fprintf,为什么需要声明为static? - Why does inline function need to be declared static if it uses fprintf? 为什么`scanf()`函数将%s和%c视为同一类型? - Why are %s and %c considered as the same type by `scanf()` function? 为什么这段代码有效? function 的输入是“string s”,但我们给出的实际输入是“int name”。 C语言 - Why does this code work? The input for the function is "string s" but the actual input we are giving is "int name". C language 函数指针类型不能用于函数原型 - Function pointer type cannot be used for a function prototype 错误:“类型名称”声明为返回函数的函数 - error: 'type name' declared as function returning a function
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM