我看到另一个关于GCC -Wshadow的帖子过于严格。我的问题是相反的。
我重新访问了一些编写的代码,并注意到-Wshadow未能按预期工作:
void free(double* x) {
free(x);
}
要么:
#include <string.h>
// other code here
int memset = 0;
两者都使用-Wshadow进行编译而没有任何警告。我相信通常的方法是:
::free(x) // for 1st example
::log(x) // when in doubt if it's my function or the log from math.h
但是,理想情况下,我希望-Wshadow捕获这些。我认为我无法正确理解GCC或C++。有人可以解释为什么它会这样工作吗?谢谢。
我用以下命令编译所有代码:
GCC-4.8.2 -static-libstdc++ -std=c++11 -pedantic -Werror -Wall -Wextra -Wshadow -Wold-style-cast
编辑为回应下面有关超载的评论:我也可以编译
void free(void* x) {
// blah
}
现在看起来好像不重载,匹配C库的确切签名。但我认为在这种情况下,编译器需要警告(-Wshadow)。关于memset:我实际上并没有编写像memset情况那样公然的代码,但是我以它为例。
Edit2 示例链接:https://groups.google.com/forum/#!topic/android-ndk/8v2M1i1-Dls
在此链接的帖子中,您不能使用-Wshadow声明诸如“abs”之类的符号。但是我可以声明“memset”,“free”等符号。GCC网站说-当内置阴影被遮盖时,-Wshadow应该发出警告。
最佳答案
遮蔽警告针对以下情况:1)发生名称隐藏,即一个名称被稍后声明的另一个名称或在更局部的范围内隐藏,2)代码仍然格式正确。
在free
的情况下,如果声明是在全局 namespace 中进行的,则您有重载,而不是重影。 (我不能马上说这种“扩展”标准库的尝试实际上是否合法。)对于memset
,再次声明如果声明是在全局 namespace 中进行的,则声明完全是非法的,即代码无效。
至于真正的真实姓名隐藏实际上发生的情况,您会发现,-Wshadow
旨在作为警告-旨在以形式上完全合法的代码捕获潜在危险的姓名隐藏。与警告一样,为了避免过度的热情和烦恼,开发人员必须以某种方式将所有隐藏名称的情况分为看起来确实可疑和可能是故意的。对于这个特定的警告,我想警告一下,当相似性质的实体之间发生隐藏时,会发出警告:一个类型会隐藏另一个类型,一个函数会隐藏另一个函数,而一个变量会隐藏另一个变量。当具有相同性质的实体彼此隐藏时,很可能会出错:用户可能会使用一个实体,而认为他们使用了另一个实体,并且代码仍会安静地编译。但是,当不同性质的实体彼此隐藏时,警告的需求就大大减少了,因为不同性质的实体具有完全不同的使用上下文/模式/语法。例如,变量用法语法通常与函数用法语法不同(当然,如果我们考虑函数对象,这并不完全准确,但在很大程度上还是正确的)。编译器可能会捕获任何意外的滥用作为错误。因此,当变量隐藏函数或函数隐藏类型时,最好不要发出阴影警告。这可能是为什么当本地-Wshadow
变量隐藏全局memset
函数时,您不会从memset
收到任何警告的原因。如果您不小心错过或忘记了本地int memset;
声明,并继续使用memset
,就好像它是一个函数(memset(dst, src, n)
),则代码将完全无法编译。此处无需任何其他警告,因为无论如何您的错误肯定会被捕获并报告。
更新:在您另外声明free
称为void free(void *)
的情况下,即完全匹配标准函数签名,您正在处理gcc“功能”之一。您实际上是在提供自己的标准库函数定义,该定义将替代“标准”定义。专门为您提供机会,将GCC库实现中的所有标准库函数声明为所谓的弱符号。在某些情况下(例如作为调试辅助工具),这是一个有用的功能,但是我们要为此付出的代价是,有可能不小心替换标准功能。
是否应该警告-Wshadow
是一个不同的问题...再次,引入-Wshadow
来警告危险的名称隐藏。在这种情况下,不会隐藏名称,并且正式而言,该代码是非法的。但GCC出于上述目的允许它。