【发布时间】:2021-05-24 07:33:54
【问题描述】:
考虑以下测试项目:
test.h:
#ifndef TEST_H
#define TEST_H
void test1(int);
void test2(int);
#endif /* TEST_H */
text.c:
#include "test.h"
void test1(int x) { (void) x; }
糟糕,我忘了定义test2()!当我这样做时,我想要一些 反馈,最好是拒绝编译,尽管至少有一个警告会很好。但是 GCC 10.2(在 Ubuntu 20.10 上)编译得很好,没有警告:
gcc -Wall -Wextra -Wpedantic -std=c11 -o libtest.o -c test.c
我想我明白为什么了:如果 test2() 实际上是来自另一个库,也许是系统库,该怎么办?让它成为最终将所有内容链接到可执行文件的程序的问题!但我想在那之前知道这件事。在这种情况下,它没有在任何包含的头文件中声明。它没有在任何地方调用。可以检测到吗?
我试过了:
-
--no-undefined导致gcc: error: unrecognized command-line option ‘--no-undefined’; did you mean ‘-Wno-undef’? -
-Wno-undef- 接受但没有警告 -
-z,defs- 接受但没有警告 -
-Wimplicit-function-declaration- 接受但没有警告 -
-Werror=missing-declarations- 我知道这是相反的情况,但我越来越绝望了。
【问题讨论】:
-
它是链接器(例如
ld)会将此称为未定义(编译器不能)。但是,因为text.c不实际上使用test2,编译器将test2的前向声明视为只是 那个。它确实没有在text.o中引用它。声明和不是用法/引用。这完全没问题,也是人们通常想要的…… -
... 例如,如果有人拨打了
#include <math.h>,但从未实际致电(例如)cos,我们不希望抱怨缺少cos如果我们从不使用它[忘记使用-lm]。在这种情况下,我们可能只需要来自.h的#define M_PI ...而不需要调用任何函数,因此我们不需要需要-lm。为了得到你想要的,添加一个用法到text.c(例如):int main(void); test1(); test2(); return 0; }链接器现在将搜索test2并且not找到它,所以它会产生一个错误。跨度> -
另一种[更被动]强制检查的方法是获取函数的地址:
#include "test.h" void test1(int x) { (void) x; } void *check_defined[] = { test1, test2 }; void main(void) { } -
您知道您的
gcc命令不会创建静态库吗?它创建了一个具有不寻常名称libtest.a的静态可执行文件。要创建静态库,您首先使用gcc -c编译.o文件,然后使用ar。 -
我收回了,您使用
-c创建了一个具有不寻常名称libtest.a的对象文件。在我的系统上file告诉我它是ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped。一个真正的静态库被描述为current ar archive。
标签: c gcc gcc-warning