使用以下代码:
int main(){
printf("%f\n",multiply(2));
return 0;
}
float multiply(float n){
return n * 2;
}
当我尝试编译时,我得到一个警告:“'%f'期望'double',但是参数的类型为'int'”和两个错误:“'multiply'的冲突类型”,“之前的隐式声明'乘以'在这里。'
问题1 :我猜这是因为,鉴于编译器在第一次碰到它时不知道函数'multiply',他将发明一个原型,并发明原型总是假设'int'都被返回并作为参数。因此,本发明的原型将是“int multiply(int)”,因此也就是错误。这是对的吗?
现在,以前的代码甚至都不会编译。但是,如果我打破两个文件中的代码:
#file1.c
int main(){
printf("%f\n",multiply(2));
return 0;
}
#file2.c
float multiply(float n){
return n * 2;
}
并执行“gcc file1.c file2.c -o file”它仍然会发出一个警告(printf期望是double但是正在获取int)但是错误将不再出现并且它将被编译。
问题2 :为什么我将代码分解为2个文件进行编译?
问题3 :一旦我运行上面的程序(版本分成2个文件),结果就是在屏幕上打印了0.0000。怎么会?我猜测编译器再次发明了一个与该功能不匹配的原型,但为什么会打印0?如果我将printf(“%f”)更改为printf(“%d”),它会打印1.再次,对幕后发生的事情的任何解释?
提前多多感谢。
答案 0 :(得分:4)
因此,本发明的原型将是“int multiply(int)”,因此也就是错误。这是对的吗?
绝对。这样做是为了向后兼容缺少函数原型的前ANSI C,并且没有类型声明的所有内容都是隐式int
。编译器编译你的main
,创建int multiply(int)
的隐式定义,但是当它找到真正的定义时,它会发现谎言并告诉你它。
为什么我将代码分成2个文件进行编译?
编译器永远不会发现关于原型的谎言,因为它一次编译一个文件:它假定multiply
接受int
,并在int
中返回main
1}},并且在multiply.c
中没有发现任何矛盾。但是,运行此程序会产生未定义的行为。
一旦我运行上面的程序(版本分成2个文件),结果就是屏幕上打印了0.0000。
这是上述未定义行为的结果。该程序将编译和链接,但由于编译器认为multiply
采用int
,它永远不会将2
转换为2.0F
,而multiply
将永远不会找出。同样,在int
函数中将float
重新解释为multiply
加倍计算的错误值将再次视为int
。< / p>
答案 1 :(得分:1)
问题1:是的,你是对的。如果没有函数原型,则默认类型为int
问题2:当您将此代码编译为一个文件时,编译器会看到已经有一个名为multiply
的函数,它的类型与假定的不同({{1}而不是double
)。因此编译不起作用。
当您将其分成两个文件时,编译器会生成两个int
个文件。在第一个中,它假设.o
函数将在其他文件中。然后链接器将两个文件链接到一个二进制文件中,并根据名称multiply()
在第一个multiply
文件中的编译器所假定的float multiply()
的位置插入int multiply()
的调用。 / p>
问题3:如果您将.o
int
视为2
,您将得到一个非常小的数字(~1 / 2 ^ 25),所以在那之后你将它乘以2并且对于格式float
它仍然太小。这就是您看到%f
。
答案 2 :(得分:1)
未指定的函数的返回类型为int
(这就是您收到警告的原因,编译器认为它返回一个整数)和未知数量的未指定参数。
如果你在多个文件中分解你的项目,只需在从其他文件调用函数之前声明一个函数原型,一切都会正常工作。
答案 3 :(得分:1)
<强>问题1:强>
因此,本发明的原型将是&#34; int multiply(int)&#34;,因此 错误。这是对的吗?
不是exactelly是因为它取决于你的Cx(C89,C90,C99,......)
对于函数返回值,在C99之前明确规定如果没有可见的函数声明,则转换器提供一个。这些隐式声明默认为返回类型int
来自C Standard的理由(6.2.5第506页)
在C90之前,没有功能原型。开发人员期望 能够互换签名和未签名的论点 相同整数类型的版本。必须施展论据,如果 函数定义中的参数类型具有不同的符号, 被视为与C的易于进行的类型检查系统和a 很少侵入性的。原型的引入并没有完全发挥作用 远离论证的可互换性问题。省略号 符号规定没有人知道1590省略号 提供没有信息的预期参数类型。同样,为 函数返回值,在C99之前明确指定了 如果没有看到功能声明,则翻译提供一个。 这些隐式声明默认为返回类型的int。如果 实际的函数碰巧返回类型unsigned int,这样的 默认声明可能返回了意外的结果。许多 开发人员对功能声明有一种随意的态度。该 我们其他人不得不忍受委员会的后果 想要打破他们写的所有源代码。该 函数返回值的可互换性现在是一个有争议的问题, 因为C99要求在...处显示函数声明 调用点(不再提供默认声明)
问题2:
为什么我将代码分成2个文件进行编译?
它将进行编译,它将被视为在第一个问题中表示为相同的