【问题标题】:C++ redefinition of variable, global namespace polluted and I don't know whyC++重新定义变量,全局命名空间被污染,我不知道为什么
【发布时间】:2015-04-12 13:34:04
【问题描述】:

所以我认为我做了一些非常愚蠢的事情,我就是想不通。以下程序让我很痛苦:

#include <iostream>
int time = 0;
int main(int argc, char **argv) {
    std::cout << "hi" << std::endl;
    return 0;
}

我的编译字符串是:clang++ -std=c++1y --verbose -stdlib=libc++ main.cpp -o main。重新定义错误是 /usr/include/time.h:116:8: note: previous definition is here--verbose 显示我这是包含路径顺序:

Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.1.0
Thread model: posix
 "/Library/Developer/CommandLineTools/usr/bin/clang" -cc1 -triple x86_64-apple-macosx10.10.0 -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -main-file-name main.cpp -mrelocation-model pic -pic-level 2 -mdisable-fp-elim -masm-verbose -munwind-tables -target-cpu core2 -target-linker-version 241.9 -v -resource-dir /Library/Developer/CommandLineTools/usr/bin/../lib/clang/6.0 -stdlib=libc++ -std=c++1y -fdeprecated-macro -fdebug-compilation-dir /Users/aliak/dev/atom/sim -ferror-limit 19 -fmessage-length 0 -stack-protector 1 -mstackrealign -fblocks -fobjc-runtime=macosx-10.10.0 -fencode-extended-block-signature -fcxx-exceptions -fexceptions -fdiagnostics-show-option -vectorize-slp -o /var/folders/r_/pmd7rtcd4h35dqsf496nyzsh0000gn/T/main-d500bd.o -x c++ /Users/aliak/dev/atom/sim/main.cpp
clang -cc1 version 6.0 based upon LLVM 3.5svn default target x86_64-apple-darwin14.1.0
ignoring nonexistent directory "/usr/include/c++/v1"
#include "..." search starts here:
#include <...> search starts here:
 /Library/Developer/CommandLineTools/usr/bin/../include/c++/v1
 /usr/local/include
 /Library/Developer/CommandLineTools/usr/bin/../lib/clang/6.0/include
 /Library/Developer/CommandLineTools/usr/include
 /usr/include
 /System/Library/Frameworks (framework directory)
 /Library/Frameworks (framework directory)

我就是不知道出了什么问题。如果我将-nostdinc++ 添加到命令行args 以clang 然后删除iostream 包含,但保留时间变量,一切正常。我猜这意味着 iostream 包括 time.h。但是我很困惑,它不应该包括ctime而不是time.h,它将所有东西都包装在std命名空间中吗?

我也尝试过删除 xcode 并重新安装。

更新:

Mats 的评论让我做了更多的窥探。因此,将 -H 传递给 clang++ 会打印出标题树。事实证明,pthread.h 是实际上包含 time.h 的那个。但 ctime 实际上也包含 time.h。这似乎符合标准,因为:“但是,在 C++ 标准库中,声明(在 C 中定义为宏的名称除外)在命名空间 std 的命名空间范围 (3.3.6) 内。它未指定这些名称是否首先在全局命名空间范围内声明,然后通过显式使用声明注入命名空间 std"

【问题讨论】:

    标签: c++ macos c++11 compilation clang


    【解决方案1】:

    time() 是标准 C 中的一个函数,这意味着它位于命名空间之外,因此可以使用 C++ 编译器编译“旧”C 代码,而不会到处乱扔using namespace std

    当您包含&lt;iostream&gt; 时,显然包含了标头time.h,这就是您获得对它的引用的原因。

    要么不要使用该名称,要么添加namespace MyName { int time; };,然后在要引用变量时使用MyName::time

    [我不知道确切的位置,但我相信 C++ 标准声明“当您包含例如 &lt;ctime&gt; 时,现有的标准库函数可能存在也可能不存在于 std:: 命名空间之外 - 实际实现的&lt;ctime&gt; 几乎可以肯定在某处包含常规的&lt;time.h&gt;。]

    例如在我的 linux 机器上的 g++ 4.9.2 标头中:

    ....
    #pragma GCC system_header
    
    #include <bits/c++config.h>
    #include <time.h>
    
    #ifndef _GLIBCXX_CTIME
    #define _GLIBCXX_CTIME 1
    
     ...     
    namespace std
    {
      ...
      using ::time;
      ...
    } // namespace
    

    libcxx 中的那个看起来几乎一模一样。

    【讨论】:

    • 好吧,如果&lt;iostream&gt; 包含&lt;time.h&gt;,则它不符合要求。包含&lt;ctime&gt; 也是如此。
    • 是的,我最终做了命名空间的事情。哦,伙计,您对 ctime 实际上包括 time.h 是正确的。我仍然不明白为什么,我认为 cname 标头是 name.h 标头的精确副本,但在 std 命名空间中。如果 C 代码包含 time.h 对 C++ 编译器来说应该不是问题,但是如果 C++ 代码想要使用 ctime,它应该得到它所追求的。
    • 似乎 pthread.h 是 iostream 的罪魁祸首。您可以将 -H 传递给编译器,它会打印出包含树
    • 哦,看看这个可爱的摘录:“然而,在 C++ 标准库中,声明(除了在 C 中定义为宏的名称)在命名空间的命名空间范围 (3.3.6) 内std.这些名称是否首先在全局命名空间范围内声明,然后通过显式使用声明注入命名空间 std" :(
    • @Deduplicator 另一种读法同样荒谬;这意味着,例如,对于 nullptr_tsize_t,没有 C++ 标头可能包含 &lt;cstddef&gt;。我不知道阅读之后有任何实现。
    猜你喜欢
    • 2012-02-10
    • 1970-01-01
    • 2017-05-15
    • 2014-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多