这是src1.c的内容:
#include <stdio.h>
extern int w;
//int go(char); // no need to declare here. WHY????
main(){
char a='f';
go(a);
printf("%d\n", w);
}
Run Code Online (Sandbox Code Playgroud)
这是src2.c的内容:
#include <stdio.h>
int w = 99;
int go(char t){
printf("%c\n%d\n",t,sizeof(t));
}
Run Code Online (Sandbox Code Playgroud)
为什么在Linux中编译go函数src1.c后,必须在文件中声明该函数?
cc src1.c src2.c;
Run Code Online (Sandbox Code Playgroud)
编译器是否将go函数的定义放在src2.cmain函数代码上面的文件中,这样就不需要声明了?
我这样做:
#include <stdio.h>
int go(char); // need to declare here, because if not, arguments of go will be promoted to intS and they would conflict with char parameters defined in go. Error is droped!
main(){
char a='f';
go(a);
}
int go(char t){
printf("%c\n%d\n",t,sizeof(t));
}
Run Code Online (Sandbox Code Playgroud)
所以每个人都说,在没有原型的情况下传递任何数量和类型的参数都是错误的.int在这种情况下,它们被提升为s,但必须同意定义中指定的那些.
我做了一些测试,发现即使它编译没有错误它也无法正常工作.
SRC1:
#include <stdio.h>
int go(int t){
printf("%d\n%d\n",t,sizeof(t));
}
Run Code Online (Sandbox Code Playgroud)
sr2.c:
#include <stdio.h>
int go(int); //if I omit this prototype, program outputs 1 which is far from correct answer :)
main(){
double b=33453.834;
go(b);
}
Run Code Online (Sandbox Code Playgroud)
所以最后答案只能是未定义的行为.
谢谢Maxim Skurydin
在使用函数之前,确实没有必要使用函数的原型,但这是C早期的一个怪癖.
当没有原型存在时,编译器无法检查传递给函数或由函数返回的实际类型,这在使用和声明不匹配的情况下可能非常糟糕.
当编译器看不到调用gowhen的原型时go(b);,它假定它具有以下原型int go(<any number of arguments can be there>).在函数调用之前对参数执行默认参数提升.当然,如果go另一个转换模块中没有函数,则会出现链接器错误.
从c99标准:
6.5.2.2函数调用
如果表示被调用函数的表达式具有不包含原型的类型,则对每个参数执行整数提升,并将具有float类型的参数提升为double.这些被称为默认参数促销.如果参数数量不等于参数数量,则行为未定义.如果使用包含原型的类型定义函数,并且原型以省略号(,...)结尾,或者促销后的参数类型与参数类型不兼容,则行为未定义.如果使用不包含原型的类型定义函数,并且促销后的参数类型与促销后的参数类型不兼容,则行为未定义,但以下情况除外:
- 一个提升类型是有符号整数类型,另一个提升类型是相应的无符号整数类型,并且该值可在两种类型中表示;
- 两种类型都是指向字符类型或void的限定或非限定版本的指针.
6.3.1.1布尔,字符和整数
2 /如果int可以表示原始类型的所有值,则该值将转换为int; 否则,它将转换为unsigned int.这些被称为整数促销 .48)所有其他类型都是
更新:
编译器是否将src2.c文件中的go函数定义放在main函数的代码上面,这样就不需要声明了?
不,它没有放任何东西.上述标准的引用表明不需要原型.每个文件都是独立编译的,所以当编译src1.c时,它不知道src2.c和go里面的函数定义.
所以每个人都说,在没有原型的情况下传递任何数量和类型的参数都是错误的.在这种情况下,它们被提升为intS,但必须同意定义中指定的那些.
这是有可能的,并且在系统范围的更改之后我遇到了一些模糊的错误,这些错误在没有任何警告的情况下编译得很好(实际上,它是未定义的行为).同样,由于每个*.c文件都是独立编译的,现在可以检查go另一个翻译单元中定义的参数数量及其函数类型.如果函数接受了您提供的更多参数,则"未使用"参数将填充一些随机数据.你应该记住,如果参数不匹配 - 它是未定义的行为,这意味着任何事情都可能发生.
| 归档时间: |
|
| 查看次数: |
1483 次 |
| 最近记录: |