未使用的“静态内联”函数生成带有“clang”的警告

67up9zun  于 2023-03-01  发布在  其他
关注(0)|答案(4)|浏览(171)

当使用gccclang时,启用多个警告通常是一个好主意,第一批警告通常由-Wall提供,这批警告相当大,包括特定的警告-Wunused-function
现在,-Wunused-function可以用来检测不再被调用的static函数,这意味着它们是无用的,因此最好从源代码中删除。当应用“零警告”策略时,它不再是“可取的”,而是完全强制的。
出于性能原因,某些函数可以直接定义到头文件*.h中,以便在编译时内联它们(不管什么LTO魔法)。这类函数一般声明和定义为static inline。过去,这类函数可能会被定义为宏,但考虑到更好的做法是将其定义为static inline函数。适用时(无滑稽类型问题)。
好了,现在我们有一堆函数直接定义到头文件中,这是出于性能的考虑。包含这样一个头文件的单元没有义务使用它所有声明的符号。因此,在头文件中定义的static inline函数可能不会被调用。
对于gcc来说,这很好。gcc会标记一个未使用的static函数,但不会标记一个inline static函数。但是对于clang,结果是不同的:如果一个单元没有调用在头文件中声明的static inline函数,则会触发-Wunused-function警告,并且不需要很多标志就可以达到这个目的:-Wall就足够了。
一个解决方法是引入一个编译器特定的扩展,比如__attribute__((unused)),它明确地告诉编译器头文件中定义的函数不一定会被它的所有单元调用。好的,但是现在,过去干净的C99代码包含了某种形式的特定编译器扩展,增加了可移植性和维护的负担。
因此,问题更多的是这种选择的逻辑:为什么clang选择在头文件中定义的static inline函数未被调用时触发警告?在哪种情况下这是个好主意?
clang提出了什么建议来覆盖头文件中定义的内联函数的相对常见的情况,而不要求使用编译器扩展?

  • edit*:经过进一步调查,该问题似乎不正确。警告是在编辑器 *(VSCode)中使用clang linter应用选定的列表编译标志(-Wall等)触发的。但是,当使用clang并使用完全相同的标志列表实际编译源代码时,“unused function”警告并不存在。

到目前为止,编辑器中可见的结果与编译时发现的结果完全相同,这是我第一次看到不同之处。
因此,问题似乎与linter使用clang生成警告列表的方式有关,这是一个更为复杂和具体的问题。
注意注解:
好的,对不起,这实际上与预期不同。似乎警告是使用clang linter和选定的编译标志 * 在编辑器 * 中触发的(-Wall等)。但是当使用完全相同的标志编译源代码时,“未使用的函数”警告实际上并不存在。到目前为止,编辑器中可见的结果过去常常与编译时找到的结果完全相同;这是我第一次看到不同之处,所以问题似乎与linter使用clang生成警告列表的方式有关,这似乎是一个[比我意识到的]更复杂的问题。

csga3l58

csga3l581#

我不确定你会找到任何“为什么”。我认为这是一个bug,可能是他们不关心修复的bug。正如你在问题中暗示的,它确实鼓励了非常糟糕的实践(使用编译器扩展进行注解,而不需要注解),这是不应该做的;相反,除非/直到错误被修复,否则警告应该被关闭。
如果你还没有,你应该搜索他们的跟踪器,寻找一个现有的bug报告,如果不存在,就打开一个。
跟进:我收到一些报告,我还没有证实这种行为只发生在直接定义在源文件中的函数上,而不是从包含的头文件中。如果是这样,它远没有那么糟糕,可能你可以忽略它。

2wnc66cl

2wnc66cl2#

在C++17和C23中有[[maybe_unused]]。它是一种独立于编译器的注解未使用的函数(和其他对象)的方法,它可靠地消除了警告,同时明确了意图。

[[maybe_unused]] int lower_limit_of_calls()
{
   return 1;
}
bbuxkriu

bbuxkriu3#

'#ifdef使用函数XYZ'
在包含头部之前,必须配置所使用的内联函数。听起来很麻烦,看起来也很笨拙。

oaxa6hgo

oaxa6hgo4#

在使用gccclang时,通常最好启用一些警告,
当使用 * 任何 * C编译器时,最好确保警告级别被调高,并注意由此产生的警告,这样可以避免大量的破坏、混乱和浪费精力。
现在,-Wunused-function可以用来检测不再被调用的static函数,这意味着它们是无用的,因此最好从源代码中删除。当应用"零警告"策略时,它不再是"可取的",而是完全强制的。
请注意
1.这种零预警政策虽然用意良好,但却是一根拐杖。我不太尊重那些以僵化的规则取代人类判断的政策。
1.这种零警告政策可以通过多种方式被颠覆,比如禁用某些警告,那么它们到底有多大用处呢?
1.政策是由选择而采取的,是达到目的的手段。也许不是你个人的选择,而是某人的选择。如果现行政策不能充分服务于预期目标,或干扰了其他目标,那么就应该重新评估它(尽管这不一定意味着它会改变)。
出于性能方面的考虑,有些函数可以直接定义到头文件*.h中,这样它们就可以在编译时内联(忽略任何类型的LTO魔术)。
这是一个选择。通常,一个提供很少的优势。
这样的函数通常被声明和定义为static inline,在过去,这样的函数可能会被定义为宏,但只要适用,最好将其定义为static inline函数(没有有趣的类型问题)。
由谁来考虑?比起宏来更喜欢函数是有原因的,但在某些情况下也有更喜欢宏的原因。并非所有这样的原因都是客观的。
包含此类头文件的单元没有义务使用其所有声明的符号。
正确。
因此,头文件中定义的静态内联函数可能不会被调用。
嗯,这是一个人认为什么是"合理"的问题。有理由想这样做是一回事,但这些理由是否超过不这样做的理由是一个判断。* 我 * 不会这样做。
因此,问题更多的是这种选择的逻辑:为什么当头文件中定义的静态内联函数没有被调用时,clang选择会触发一个警告?2在哪种情况下这是一个好主意?
如果我们承认这是一个有意的选择,那么就可以假定Clang开发人员对您所提倡的做法的合理性有不同的看法。您应该将其视为实现质量问题,因为在这种情况下编译器是否应该发出诊断信息并没有规则。如果他们对应该警告什么有不同的想法,那么不同的编译器可能会更合适。
此外,如果您没有零警告策略,也不会有什么后果,因此您的多个选择会给您带来问题。
clang提出了什么建议来覆盖头文件中定义的内联函数的相对常见的情况,而不要求使用编译器扩展?
我怀疑Clang或它的开发者在这里提出了任何特定的行动方案。你似乎认为他们做错了什么。他们没有。他们做的事情对你来说是不方便的,因此你(可以理解)不喜欢。你肯定会找到其他人同意你的观点。但这一切都没有让Clang承担任何责任来解决问题。
也就是说,您可以尝试将头文件中的函数定义为extern inline,而不是static inline。然后,您也必须在整个程序中的某个地方为每个函数提供一个非内联定义,但这些定义可以在其他方面与内联定义相同。我推测,这可能会缓解Clang。

相关问题