关于C函数原型和编译的问题
使用以下代码:
int main(){
printf("%fn",multiply(2));
return 0;
}
float multiply(float n){
return n * 2;
}
当我尝试编译时,我得到一个警告:''%f'期望'double',但参数的类型为'int'“和两个错误:”'multiply'的冲突类型'','先前的'multiply'的隐式声明为这里。”
问题1 :我猜测这是因为,当编译器第一次遇到函数时,他不知道函数“multiply”,他会发明一个原型,并且发明原型总是假设'int'被返回并且被视为参数。 所以本发明的原型将是“int multiply(int)”,因此也是错误。 它是否正确?
现在,以前的代码甚至不会编译。 但是,如果我在两个文件中分解代码,如下所示:
#file1.c
int main(){
printf("%fn",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.再次说明幕后发生的事情?
提前致谢。
所以本发明的原型将是“int multiply(int)”,因此也是错误。 它是否正确?
绝对。 这是为了向后兼容缺少函数原型的pre-ANSI C,并且没有类型声明的所有内容都是隐式int
。 编译器编译你的main
,创建一个int multiply(int)
的隐式定义,但是当它找到真正的定义时,它发现了谎言,并告诉你它。
当我将代码分解成两个文件编译时,该怎么办?
编译器从来没有发现关于原型的谎言,因为它一次编译一个文件:它假定multiply
接受一个int
,并在main
返回一个int
,并且在multiply.c
找不到任何矛盾。 但是运行这个程序会产生未定义的行为。
一旦我运行上面的程序(版本分成2个文件),结果是0.0000被打印在屏幕上。
这是上述未定义行为的结果。 该程序将编译和链接,但由于编译器认为multiply
需要一个int
,它不会将2
转换为2.0F
,并且multiply
将永远不会找出。 同样,通过加倍的计算不正确的值int
重新解释为一个float
的内multiply
函数将被作为治疗int
一次。
未指定的函数的返回类型为int
(这就是为什么你会得到警告,编译器认为它返回一个整数)以及未知数量的未指定参数。
如果你在多个文件中分解你的项目,只需在从其他文件中调用函数之前声明一个函数原型,并且所有的都可以正常工作。
问题1:
所以本发明的原型将是“int multiply(int)”,因此也是错误。 它是否正确?
不完全是,因为它取决于你的Cx(C89,C90,C99,...)
对于函数返回值,在C99之前,明确规定如果没有可见的函数声明,则翻译器提供一个函数声明。 这些隐式声明默认为int的返回类型
来自C标准的理由(第6.2.5页第506页)
在C90之前,没有功能原型。 开发人员希望能够交换已签名和未签名相同整数类型版本的论据。 如果函数定义中的参数类型具有不同的符号性,那么必须抛出一个参数,这被看作是与C的易于类型检查系统相反并且有点侵入性。 原型的引入并没有完全消除争论的互换性问题。 省略号表示没有任何关于1590省略号的已知信息,没有提供预期的参数类型信息。 同样,对于函数返回值,在C99之前,明确规定如果没有可见的函数声明,则翻译器提供一个函数声明。 这些隐式声明默认为int的返回类型。 如果实际函数发生返回unsigned int类型,则此类默认声明可能会返回意外的结果。 很多开发人员对功能声明持有随意的态度。 我们其他人不得不忍受委员会不想破坏他们编写的所有源代码的后果。 函数返回值的互换性现在是一个争议点,因为C99要求函数声明在调用点可见(不再提供默认声明)
问题2:
当我将代码分解成两个文件编译时,该怎么办?
它将会被编译,并且会像第一个问题中所指出的一样被处理
链接地址: http://www.djcxy.com/p/79907.html