调用 undefined/undeclared 函数的已编译 C 程序;没有错误或警告报告。为什么?

Compiled C program with call to undefined/undeclared function; no error or warning reported. Why?

我正在复制 Kernighan & Ritchie 的 "C Programming Language (2nd Edition)" 中的示例。为了确保我已正确复制代码(并测试其功能),我编译了这段代码:

/*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);,同时在 main() 中保持对 qsort() 的调用处于活动状态,只是为了看看我是否会引发错误,但程序仍然设法编译 并且 运行 默默无闻,没有抱怨或意外行为

这是怎么回事?

问题是你没有包含头文件,你包含了完整的 source 文件,创建了一个 translation unit。由于这些函数都在这些包含的文件中声明和定义,因此您不会出错,因为编译器 具有 声明。

如果您分开编译,并分别编译每个源文件(并删除那些包含指令),那么如果没有错误,您至少会收到警告。

qsort()包含在<stdlib.h>中;所以即使我调用这个函数的参数对编译器没有任何意义,在通过库包含它之后引用 qsort() 似乎是完全合法的。

@mfro 如果你 post 的回答说的是这方面的内容,我会把你的回答归功于你。

qsort是一个标准库函数,声明在<stdlib.h>.

编译器需要qsort的可见声明,并且您已在源文件中提供了这样的声明.

linker需要定义 qsort;这是由标准 C 库提供的。该函数与您的声明不兼容,但这不是 link 用户通常可以检测到的错误。

因为您以与实际函数不兼容的方式声明了标准库函数,所以您的程序具有未定义的行为。

至于为什么您的程序在您删除 qsort 的声明后仍然可以编译,那是因为它遵循旧版本的 C 标准。从 C90 标准开始,调用没有可见声明的函数是合法的;编译器 假定 函数 returns 是 int。 C99 放弃了 "implicit int" 规则,要求对此类调用进行 compile-time 诊断——但默认情况下 gcc 仍遵循 C90 标准(带有 gcc-specific 扩展)。使用 -std=c99-std=c11 要求 gcc 符合更现代的 C 标准版本;添加 -pedantic -Wall -Wextra 以获得更多警告。

这就是让编译器诊断错误的方法(尝试重新声明 qsort)。要 修复 该错误,您需要使用 qsort 以外的名称 并且 您需要提供有效的声明和定义。

此外,.c 文件的 #include 指令很少有意义。通常 .c 文件(提供定义)是单独编译的,.h 文件(提供声明)是 #included。这是一个约定,而不是语言规则,但是遵循它可以使组织代码变得更加容易。还有更多关于如何做到这一点的知识(header 守卫,如何 link 多个 objects 到一个程序中,等等),但这超出了这个问题的范围。