在C ++中使用C头时,避免全局变量/方法名称冲突

时间:2010-07-07 17:29:13

标签: c++ namespaces

我最近花了一些时间追逐一个烦人的小虫子,我正在为那些遇到过同样问题或者知道避免它的最佳方法的人寻找建议。

我遇到的情况是我使用C ++进行开发并使用strerror,因此我使用类似的东西

extern "C" {
#include <string.h>
}

#include <cstring>,btw的情况相同)。现在,在该文件中定义了一个函数,如下所示:extern char *index (__const char *__s, int __c)这个函数带来了我最初有一个类似于以下结构的乐趣:

for (int index = 0; index != condition (); ++index) {
   // do something with buffer[index] here
}

log->write ("Final value of index: %d\n", index); // <- Ooops!!!

但是我没有得到编译错误,而是出现虚假输出。我的编译器(g ++)标志设置得相当高,以下内容没有抓住这个:

-W -Wall -Wextra -Werror -Wshadow -Wformat -pedantic -ansi

我也不能像#undef那样使用<cstring>技巧,因为这不是宏。

我的问题是其他人是否遇到过同样的问题,最佳解决方案是什么?理想情况下,我很想听听一些模糊的g ++功能,如-use-the-force-luke=...;)

请注意,我不是在问如何解决这个完全问题;我只能更改变量名称。我正在寻找有关如何避免将来出现这种情况的提示。

编辑:

由于James Curran的回复,我想我应该澄清一下。我不是在看为什么不应该这样。据我所知,在没有局部变量的情况下,范围空间得以扩展。我感到惊讶的是,我没有可以设置的标志警告这一点。我认为-Wshadow会捕获它,因为它在类范围内捕获变量/方法阴影,但我离题了。

我感兴趣的是一种通知本地名称与非本地范围冲突的方法。有人提到,如果我使用流操作而不是可变参数调用,我会抓住这个特定的错误。确实如此,但即使以下情况也不会产生g++ (GCC) 4.1.1 20070105 (Red Hat 4.1.1-51)和以下标志-W -Wall -Wextra -Werror -Wshadow -ansi -pedantic的警告/错误。

#include <iostream>
#include <cstring>

int main () {
        int index = 42;
        std::cerr << index << std::endl;
        return 0;
}

这对我很好奇。

4 个答案:

答案 0 :(得分:7)

首先,看起来您正在使用printf样式的可变参数列表,这会导致类型安全性立即丢失。你应该在C ++中避免这种设计。

如果你必须这样做,那么你可以考虑装饰函数声明来告诉gcc它是一个类似printf的函数,如果你的参数列表与你的格式字符串不匹配,它会给你警告。对于标准*printf函数。

E.g。

void write(const char* f, ...) __attribute__((format (printf, 2, 3)));

答案 1 :(得分:2)

这只是C ++范围规则的结果 - 以下代码很好:

int f() {
    return 42;
}


int main() {
    for ( int f = 0; f < 10; f++ ) {
    }
}

我认为您无法让编译器为此生成诊断信息 - 通常认为这是可取的!

答案 2 :(得分:0)

是的,这是一个恼人的问题,尤其是。使用OS标题,例如&lt; windows.h&gt;或者&lt; Cocoa.h&gt;,经常使用宏或全局名称空间污染是常态。除了对编码更加谨慎之外,你无能为力,尽管我发现在一个不错的IDE中使用定义检查功能有助于识别名称的定义。

答案 3 :(得分:0)

让我们一步一步看看这个步骤;

  • 您包含一个标题,用于定义您不知道的标识符。 (不可避免的)
  • 您在代码中使用相同的标识作为不同的类型(合法的,并且可能是您可以接受的)
  • 您不小心在范围之外使用该变量(不幸但偶尔会发生)
  • 编译器使用外部作用域中定义的标识符,而不是给出上述错误。 (正是按照标准应该做的事情。)

所以,问题真的变成了,“你有什么期望呢?” “和”如何在不破坏大量现有代码的情况下实现这一点?“

实际上,真正的问题是,“为什么你在<cstring>中遇到这个问题,它将函数包装在命名空间std中?” - 意味着该函数实际上将被称为std :: index()。你并没有完全破坏这一点:

using namespace std;