我有许多C源文件(.c和.h文件)。头文件包含许多功能。在这些函数中,只有部分用于源.C文件。假设a.h,b.h是头文件,a.c和b.c是.c文件。 a.h包含在a.c中。但只有一些功能在一个。使用h并且不使用休息。编译后我发现以下警告:
function XXXX defined but not used.
但是那些未在a.c中使用的XXXX函数在b.c中使用。所以,我也无法完全删除这些功能。因此,我决定创建一个单独的文件,只包含那些XXXX函数,并将其包含在任何使用它的位置。这样做会创建多个头文件。任何人都可以建议我采取一些有效的方法来解决这个问题。
答案 0 :(得分:67)
“功能已定义但未使用”警告仅针对具有内部链接的函数发出,即声明为static
的函数。这些函数只能在一个转换单元中访问,因此编译器始终知道它们是否被使用(在程序中)。如果您没有在翻译单元中引用这些功能,则会知道这些功能未使用,并且会生成警告。
你说这些函数“不是在a.c中使用,而是在b.c中使用”。这不是真的。当您在头文件中将函数声明(并定义)为static
时,包含该头文件的每个转换单元都会获得该函数的内部副本。即使这些功能看起来完全相同,它们仍然是独立的,完全独立的功能。它们具有相同的名称并由相同的代码组成的事实对编译器没有任何意义。因此,在b.c
中,您获得了一个完全独立的函数副本(正如您所说),但a.c
中的完全独立副本仍未使用。
在这种情况下的问题是为什么你这样做。为什么在地球上你在头文件中定义静态函数?如果你真的需要这样做(即如果你真的想在每个翻译单元中产生这个函数的单独内部“克隆”),你可以通过使用一些特定于编译器的方法来解决警告。例如,在GCC中,您可以使用__attribute__((unused))
声明该函数,将不再发出此函数的警告。
但通常不需要在头文件中定义函数。通常一个人使用带有外部链接的函数(即没有static
),在其中一个.c文件中定义它并将声明(原型)放在头文件中。在这种情况下,编译器不会发出任何警告,即使该函数已声明但未在某些翻译单元中使用。
答案 1 :(得分:8)
答案 2 :(得分:7)
作为"不要做"的替代方案,请考虑以下内容 - 一组将触发最多三个未使用的功能警告的功能。
static int get_version_number(void) { return 42; }
static double hidden_global_variable(void) { return 3.14; }
static int potential_alternative_to_macro(int x) { return 4 * x; }
编写另一个函数,可能基于头文件的名称,
static void wno_unused_myheadername(void)
{
/* don't need to actually call the functions to avoid the warnings */
(void)&get_version_number;
(void)&hidden_global_variable;
(void)&potential_alternative_to_macro;
return;
}
我们现在发现一个未使用的功能警告。如果在包含标题的文件中声明的任何外部函数中添加对wno_unused_myheadername()的调用,则整组未使用的函数警告将消失。因为它们现在都被使用了。
编译器将从所有未使用的函数中删除所有未使用的函数,包括wno_unused_myheadername,因为它可以看到所有定义,并且可能确定对wno_unused函数的单个调用实际上没有做任何事情。
我已经检查过上面删除了clang和gcc下预期的警告,你的milage可能会因其他编译器而异。我没有查看asm输出来调查几乎未使用的函数被剥离的时间。
至于为什么 - 一个很好的理由是使用很多非常适合C89内联的小函数,它们没有内联关键字,不需要编译器的链接时间优化。
答案 3 :(得分:5)
听起来您的问题是您在.h
文件中定义功能。不要那样做。相反,只需将声明放在.h
文件中,并使用包含函数定义的匹配.c
文件:
<强> COMMON.H:强>
#ifndef _COMMON_H
#define _COMMON_H
int foo(int a, int b);
int bar(double x, double y, double z);
#endif /* _COMMON_H */
<强> common.c中:强>
#include "common.h"
int foo(int a, int b)
{
/* code */
}
int bar(double x, double y, double z)
{
/* code */
}
然后,您的a.c
和b.c
应#include "common.h"
,并且您需要安排将common.c
编入整个计划。
答案 4 :(得分:5)
另一种可能性是将这些功能定义为inline
而不是static
。在这种情况下,需要在标题中定义它们,以便定义在调用它们的任何位置都可见。
编译器将在每个使用该函数的地方内联代码,因此请注意这是您真正想要的。 Here's an answer对这些权衡进行了很好的讨论。
答案 5 :(得分:-1)
似乎没有人提到.h文件中的静态函数定义在C语言中可以创建非常好的类型化的宏。我认为这是使用这种类型的构造的一种非常有效的方法,但是当然需要对其进行警告了
caf提出的common.c / common.h解决方案建议可以解决这种警告,但是会为您可能不需要的每个函数实例生成一个函数调用。