调用 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
文件(提供声明)是 #include
d。这是一个约定,而不是语言规则,但是遵循它可以使组织代码变得更加容易。还有更多关于如何做到这一点的知识(header 守卫,如何 link 多个 objects 到一个程序中,等等),但这超出了这个问题的范围。
我正在复制 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
文件(提供声明)是 #include
d。这是一个约定,而不是语言规则,但是遵循它可以使组织代码变得更加容易。还有更多关于如何做到这一点的知识(header 守卫,如何 link 多个 objects 到一个程序中,等等),但这超出了这个问题的范围。