【发布时间】:2011-10-11 10:17:51
【问题描述】:
序言:我的 C 可能相当生锈;我在 1993 年左右开始编写 C 程序——当时的编译器可能有所不同,但我记得当尝试引用未声明的 C 函数时,编译器会中止。这是凭记忆。
目前,当我 [故意] 不匹配或省略下面的 bar 的声明(其定义在 bar.c 中)时,我很困惑为什么 GCC (4.4.3) 对我如此宽容。因为编译器没有警告我,所以程序在运行时会出现致命的寻址错误——因为bar 想要一个地址并且给定了一个整数,所以它最终将该整数取消引用为地址。
一个严格的编译器,或者我认为,会因错误而中止我。我错过了什么吗?我的构建命令行如下:
cc -o foobar -g -Wall -std=c99 -fexec-charset=ISO-8859-1 -DDEBUG foo.c bar.c
与foo.c:
int main() {
int a;
bar(a);
return 0;
}
和bar.c:
void bar(int * a) {
*a = 1;
}
我故意省略了bar 的声明,并且如前所述,故意将其传递给它一个整数(实际上可能是任何东西),而不是它的实际定义否则会要求的地址。因为$(CC) 并没有阻止我,所以我最终遇到了分段错误(x86,Ubuntu 10.04)。我知道一个兼容的 C(C99?)编译器会隐式地为 bar 创建一个 int bar(void) 声明,如果没有找到其他方法,但在这种情况下,这显然不是我想要的!
我想保护自己免受此类错误的影响——我犯了不匹配声明和定义或完全忽略前者的人为错误。
我尝试在没有链接步骤的情况下调用编译器(使用-c 开关)——但这并不重要,因为编译仍然会成功并出现警告。虽然链接器可能会抱怨,但我希望编译器在发生这种情况之前阻止我。
我不实际上想把我所有的警告变成错误(例如-Werror),因为:
- 我本可以在
foo.c的顶部包含错误的float bar(double a);,这将完全消除警告,但不会改变结果程序崩溃的事实;唉,这个程序编译成功而没有警告(即使使用-Wall开关)但仍然有问题 - 我已经并且将会有其他类型的警告,这些警告应该保持警告而不妨碍成功构建程序
- 它将处理问题的影响,而不是问题本身
- 这不仅仅是警告的类型,还有它的特定实例;我不想将特定警告变成错误,因为在某些情况下不适用;如果解决方案没有考虑到警告发生的具体情况和上下文,这将过于“粗略”
【问题讨论】:
-
不回答这个问题,但是使用 C++ 编译器(隐式声明是完全禁止的)可以解决所有问题。 (可能仅在不匹配的声明/定义的链接时,但仍被捕获。)
-
@Mat 是的,我知道这一点。感谢您的提醒。不能在这里使用 C++。我确实解决了这个问题,但会等待一些替代方案,然后发布我自己的答案。