函数原型告诉编译器一些参数函数接受参数的数据类型和函数的返回类型。通过使用此信息,编译器将通过函数定义和函数调用交叉检查函数参数及其数据类型。如果我们忽略函数原型,程序编译时可能会出现警告,并且可能会正常工作。但有时,它会给出奇怪的输出,很难找到这样的编程错误。让我们看看例子
#include <errno.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp;
fp = fopen(argv[1], "r");
if (fp == NULL) {
fprintf(stderr, "%s\n", strerror(errno));
return errno;
}
printf("file exist\n");
fclose(fp);
return 0;
}
上面的程序检查命令行提供的文件是否存在,如果给定的文件存在,则程序将打印“file exists”,否则将打印相应的错误消息。让我们提供一个文件系统中不存在的文件名,并检查x86_64体系结构上程序的输出。
[narendra@/media/partition/GFG]$ ./file_existence hello.c
为什么这个程序崩溃了,相反,它应该显示适当的错误消息。此程序在x86架构上运行良好,但在x86_64架构上会崩溃。让我们看看代码有什么问题。仔细检查程序,我故意没有包括“strerror()”函数的原型。此函数返回“指向字符的指针”,它将根据传递给此函数的errno打印错误消息。请注意,x86体系结构是一个ILP-32模型,这意味着整数、指针和long都是32位宽的,这就是为什么程序可以在这种体系结构上正常工作的原因。但x86_64是LP-64模型,这意味着长指针和指针都是64位宽。在C语言中,当我们没有提供函数的原型时,编译器假设函数返回一个整数。在我们的示例中,我们没有包含“string.h”头文件(strerror的原型在此文件中声明),这就是为什么编译器假定函数返回整数的原因。但它的返回类型是指向字符的指针。在x86_64中,指针是64位宽,整数是32位宽,这就是为什么从函数返回时,返回的地址会被截断(即32位宽的地址,它是x86_6.4上整数的大小),这是无效的,当我们尝试取消引用此地址时,结果是分段错误。
现在包括“string.h”头文件并检查输出,程序将正常工作。
[narendra@/media/partition/GFG]$ ./file_existence hello.c
没有此类文件或目录
再看一个例子。
#include <stdio.h>
int main(void)
{
int *p = malloc(sizeof(int));
if (p == NULL) {
perror("malloc()");
return -1;
}
*p = 10;
free(p);
return 0;
}
>> 本文固定链接: http://www.vcgood.com/archives/4827