使用C库中的符号而不是通过名称空间std,是否有GCC警告? 考虑以下(BUGGY)C++代码: #include <cmath> #include <cstdlib> #include <iostream> int main() { if (abs(-0.75) != 0.75) { std::cout << "Math is broken!\n"; return 1; } else { return 0; } }

使用C库中的符号而不是通过名称空间std,是否有GCC警告? 考虑以下(BUGGY)C++代码: #include <cmath> #include <cstdlib> #include <iostream> int main() { if (abs(-0.75) != 0.75) { std::cout << "Math is broken!\n"; return 1; } else { return 0; } },c++,gcc,compiler-warnings,global-namespace,C++,Gcc,Compiler Warnings,Global Namespace,在GCC上,我在不同的环境中得到了不同的结果,但我还没有弄清楚环境的哪些细节是相关的。不过,更常见的选择是它调用Cabs函数。然而,即使使用-Wall-Wextra-pedantic,它也不会给出警告。我可以使用-Wfloat conversion强制发出警告,但这会给我的代码库的其余部分带来太多误报(也许我应该修复,但这是另一个问题): :在函数“int main()”中: :7:18:警告:转换为“int”会改变“double”常量值[-Wfloat转换] 如果(绝对值(-0.75)!=0.

在GCC上,我在不同的环境中得到了不同的结果,但我还没有弄清楚环境的哪些细节是相关的。不过,更常见的选择是它调用C
abs
函数。然而,即使使用
-Wall-Wextra-pedantic
,它也不会给出警告。我可以使用
-Wfloat conversion
强制发出警告,但这会给我的代码库的其余部分带来太多误报(也许我应该修复,但这是另一个问题):

:在函数“int main()”中:
:7:18:警告:转换为“int”会改变“double”常量值[-Wfloat转换]
如果(绝对值(-0.75)!=0.75){
^

当命名空间
std
中的版本过载时,每当我通过全局命名空间使用库函数时,是否有方法获取警告?

此代码将让您检测特定环境中是否存在陷阱:

double (*)(double) = &::abs; // fails if you haven't included math.h, possibly via cmath

但是它不会帮助您发现落入陷阱的位置。

这将是一件困难的事情。GCC
标题只包括
\undes
其宏(以防万一)定义了C++函数作为内联函数,使用了从代码<>代码>中的标识符。大多数函数实际上是指编译器构建:例如,代码< > STD::ABS是用<代码> 由于
和您的“buggy程序”都在同一个翻译单元中,很难看出可见性是如何分离的:如何允许
中的内联函数使用
东西,而您的代码却不使用

嗯,有以下方法:
必须重写,以便为它需要从
中获取的任何内容提供自己的局部范围声明,而不是实际包含该头

我们可以做的是准备一个头文件,用
\uuuu属性\uuuu((不推荐))
重新声明我们不想要的函数:

链接器警告会更简单。我试过了;问题是这个测试程序实际上没有生成对
abs
的外部引用(即使
中有一个
#undef abs
)。调用是内联的,因此避开了链接器警告

更新: 继DanielH的评论之后,我提出了一个改进的技巧,它允许
std::abs
,但阻止
abs

#include <cmath>
#include <cstdlib>
#include <iostream>

namespace proj {
  // shadowing declaration
  int abs(int) __attribute__ ((deprecated));

  int fun() {
    if (abs(-0.75) != 0.75) {
      std::cout << "Math is broken!\n";
      return 1;
    } else {
      return std::abs(-1); // must be allowed
    }
  }
}

int main() {
  return proj::fun();
}
使用这种方法,我们只需要一个名称列表,并将其转储到某个标题中,该标题提供以下内容:

int abs, fabs, ...; // shadow all of these as non-functions

我在 G++< /Cord>命令行中使用了<代码> -STDC++ + 98代码/代码>,强调这只是旧式的C++<代码>命名空间< /C>语义>工作。

< P> >这里有一个解决方案。我不满意它,但它可能对你有用:

namespace DontUseGlobalNameSpace {
// put all std functions here you want to catch
int abs(int x);
}
using namespace DontUseGlobalNameSpace;

现在,如果您不加限制地使用
abs()
,您将得到一个“符号不明确”错误。

不要垃圾邮件标签。C没有代码> STD< /Cord>名称空间。@奥拉夫你是对的。这只是相关的,因为C++包含C标准库的大部分,但是这并不能使C专业知识对回答这个问题有用。抱歉。这似乎是同一个问题,但我猜答案是不令人满意的。Out:使用C++代码的C函数永远不能证明C标记、标准库或任何其他库。否则每个程序都需要标记,甚至PHP或Python使用这些函数。@奥拉夫,我的意思是,如果在获得MCVE的过程中,得到的代码作为C代码有效(并且呈现相同的问题)。即使原始代码是C++,我认为使用C标记是合适的。如果我的问题是这样,MCVE依赖C++特性,那么标签是不合适的。但是,代码< CMAS> <代码>的GCC实现将它们放入<>代码STD< /Cord>命名空间中,使用:< ABS;< /C> >等。结束;如果将
return 1;
替换为
return std::abs(-1)
它仍然警告不赞成使用。@DanielH我明白了:它是用
使用
引入它们,然后只是添加一些重载。哎哟!所以主文件继承了警告,只有重载是安全的。这太糟糕了。所以除非g++头被消毒,否则当
:abs
时就需要警告了>abs
被使用,但在使用
std::abs
时不会使用,即使
std::abs
是前两个的别名。是的,这就是我想要的。不过我不知道它是否存在。可能值得注意的是
abs(int)
cstdlib
中,而不是
cmath
中,这会起作用,但它需要列举所有有争议的方法。浏览CPPPreference或标准并查找这些方法不会超过一个小时,但它仍然不理想,并且可能会遗漏一些内容。它还需要包含
dont在所有源文件的顶部使用globalnamespace.hpp
,我可以使用
sed
或其他方法来完成,但这肯定不是一个理想的解决方案。尤其是在持续的基础上,现在解决所有问题要比确保在更新代码时它们保持不变更容易。是的,这就是为什么我不满意此解决方案的原因:)编译器通常有一个包含文件的选项。例如,gcc有一个
-include
来包含一个文件,就好像你在文件的开头包含了它一样。哦,很好,我不知道。这可能足以让我使用这个解决方案,不过现在我会等待其他人是否有更好的答案。因为没有人有更好的答案更好的主意周末我可能会试试这个。如果它最终在实践中奏效,我会接受它。
$ g++ -Wall  buggy.cc
buggy.cc: In function ‘int main()’:
buggy.cc:9:7: warning: ‘int abs(int)’ is deprecated [-Wdeprecated-declarations]
   if (abs(-0.75) != 0.75) {
       ^~~
In file included from /usr/include/c++/6/cstdlib:75:0,
                 from buggy.cc:4:
/usr/include/stdlib.h:735:12: note: declared here
 extern int abs (int __x) __THROW __attribute__ ((__const__)) __wur;
            ^~~
buggy.cc:9:16: warning: ‘int abs(int)’ is deprecated [-Wdeprecated-declarations]
   if (abs(-0.75) != 0.75) {
                ^
In file included from /usr/include/c++/6/cstdlib:75:0,
                 from buggy.cc:4:
/usr/include/stdlib.h:735:12: note: declared here
 extern int abs (int __x) __THROW __attribute__ ((__const__)) __wur;
            ^~~
#include <cmath>
#include <cstdlib>
#include <iostream>

namespace proj {
  // shadowing declaration
  int abs(int) __attribute__ ((deprecated));

  int fun() {
    if (abs(-0.75) != 0.75) {
      std::cout << "Math is broken!\n";
      return 1;
    } else {
      return std::abs(-1); // must be allowed
    }
  }
}

int main() {
  return proj::fun();
}
#include <cmath>
#include <cstdlib>
#include <iostream>

namespace proj {
  // shadowing declaration
  class abs;

  int fun() {
    if (abs(-0.75) != 0.75) {
      std::cout << "Math is broken!\n";
      return 1;
    } else {
      return std::abs(-1); // must be allowed
    }
  }
}

int main() {
  return proj::fun();
}

$ g++ -std=c++98 -Wall  buggy.cc -o buggy
buggy.cc: In function ‘int proj::fun()’:
buggy.cc:10:18: error: invalid use of incomplete type ‘class proj::abs’
     if (abs(-0.75) != 0.75) {
                  ^
buggy.cc:7:9: note: forward declaration of ‘class proj::abs’
   class abs;
         ^~~
buggy.cc:16:3: warning: control reaches end of non-void function [-Wreturn-type]
   }
   ^
int abs, fabs, ...; // shadow all of these as non-functions
namespace DontUseGlobalNameSpace {
// put all std functions here you want to catch
int abs(int x);
}
using namespace DontUseGlobalNameSpace;