编译C程序,调用未定义/未声明的函数;没有报告错误或警告。为什么?

时间:2015-01-19 20:57:20

标签: c gcc

我是从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(),只是为了看看我是否可能导致错误,但程序仍然设法编译并运行默默地,无抱怨或意外行为

这里发生了什么?

3 个答案:

答案 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如果你发布一个答案说出这个效果,我会给你答案。