我是从Kernighan&amp ;;复制一个例子。 Ritchie" C编程语言(第2版)"。为了确保我已正确复制代码(并测试其功能),我编译了这段代码:
/*This is an example program from chapter 5, section 6 (Pointer Arrays; Pointers to Pointers)*/
#include <stdio.h>
#include <string.h>
#include "/home/alecto/Compsci/Cprogramming/Utils/get_line.c"
#include "/home/alecto/Compsci/Cprogramming/Kernighan_Ritchie_5/alloc.c"
#define MAXLINES 5000 /*max number of lines to be sorted*/
char *lineptr[MAXLINES]; /*pointers to lines of text*/
int readlines(char *lineptr[], int nlines);
void writelines(char *lineptr[], int nlines);
void qsort(char *lineptr[], int left, int right);
/* sort input lines */
main()
{
int nlines; /* number of input lines read */
if ((nlines = readlines(lineptr, MAXLINES)) >= 0) {
qsort(lineptr, 0, nlines-1);
writelines(lineptr, nlines);
return 0;
}
else {
printf("error: input too big for sort\n");
return 1;
}
}
... //readlines() and writelines() are defined in my source file, but not
... //qsort()
尽管源文件中没有qsort()
的定义,但程序编译时没有来自gcc或链接器的投诉。我试着在声明void qsort(char *lineptr[], int left, int right);
的同时将qsort()
的活动留在main()
,只是为了看看我是否可能导致错误,但程序仍然设法编译并运行默默地,无抱怨或意外行为
这里发生了什么?
答案 0 :(得分:3)
qsort
是标准库函数,在<stdlib.h>
中声明。
编译器需要qsort
的可见声明,并且您在源文件中提供了这样的声明。
链接器需要qsort
的定义;这是由标准C库提供的。该函数与您的声明不兼容,但这不是链接器通常可以检测到的错误。
因为您已经以与实际函数不兼容的方式声明了标准库函数,所以您的程序具有未定义的行为。
至于为什么你的程序在删除你的qsort
声明时仍会编译,那是因为它遵循旧版本的C标准。从C90标准来看,调用没有可见声明的函数是合法的;编译器假设该函数返回int
。 C99删除了“隐式int
”规则,需要对此类调用进行编译时诊断 - 但gcc默认仍遵循C90标准(使用gcc特定扩展)。使用-std=c99
或-std=c11
要求gcc符合C标准的更现代版本;添加-pedantic -Wall -Wextra
以获取更多警告。
这是如何让编译器诊断您的错误(尝试重新声明qsort
)。要修复该错误,您需要使用qsort
和以外的名称来提供有效的声明和定义。
此外,对#include
文件使用.c
指令很少有意义。通常.c
个文件(提供定义)是单独编译的,.h
个文件(提供声明)是#include
d。这是一个约定,而不是语言规则,但遵循它会使组织代码更容易。还有更多要知道如何做到这一点(标题保护,如何将多个对象链接到一个程序等),但这超出了这个问题的范围。
答案 1 :(得分:1)
问题是你没有包含头文件,你包括完整的源文件,创建一个translation unit。由于函数在这些包含的文件中声明和定义,因此编译器具有声明时不会出现错误。
如果你分开了编译,并分别编译了每个源文件(并删除了那些包含指令)那么你至少会得到错误警告。
答案 2 :(得分:1)
qsort()
包含在<stdlib.h>
中;所以即使我对这个函数的调用中的参数对编译器没有任何意义,在通过库包含它之后引用qsort()
似乎是完全合法的。
@mfro如果你发布一个答案说出这个效果,我会给你答案。