C++中的extern "C"在命名空间前缀解析和优化级别依赖方面的应用

7

我有一个名为“test.cxx”的文件,其中包含以下内容:

namespace net {
    extern "C" {
#include <arpa/inet.h>
    }
}

int main() {
    htons(1024);
}

使用-O1或更高版本编译时,一切正常。

使用-O0编译时:

error: ‘htons’ was not declared in this scope
suggested alternative: ‘net::htons’

然后我将 htons 改为 net::htons

使用 -O0 编译时一切正常。

使用 -O1 或更高级别编译时:

error: expected unqualified-id before ‘(’ token

在gcc-4.9.2和clang-3.7.0上重现了这个问题。 有人能解释一下为什么会发生这种情况吗?


5
你为什么要在net命名空间里包含inet.h头文件? - Mohit Jain
2
实际上,编译器和静态分析器应该在有人尝试这样做时发出警告。 - Alexander Oh
1个回答

13

这是因为在 -O0 下,调用被编译为 htons 函数,而你为该函数声明了 namespace net。在优化版本(例如 -O2)中,该调用将被替换为宏。

你可以通过使用 gcc -O0 -Egcc -O2 -E 预编译程序来验证这一点。

当使用 htons 时
-O2 下,htons 被翻译为

int main() {
    (__extension__ (
       {
          register unsigned short int __v, __x = (unsigned short int) (1024);
          if (__builtin_constant_p (__x))
             __v = ((unsigned short int) ((((__x) >> 8) & 0xff) | (((__x) & 0xff) << 8)));
          else
             __asm__ ("rorw $8, %w0" : "=r" (__v) : "0" (__x) : "cc");       
          __v;
      }
    ));
}

使代码不抛出解析错误。

错误:'htons' 在此作用域中未声明

当使用 net::htons 时

当您将 ntohs 替换为 net::ntohs 时,ntohs 宏定义被用于优化并且你的预编译代码会变成:

int main() {
  net::(__extension__ ({... /* removed for Brevity */ ...}));
}

因此产生了错误

错误:在‘(’令牌之前需要无限定ID

为什么会发生这种情况
htons 可以被实现为函数或宏。如果它被定义为宏,htons 将正常工作。但是,如果它被定义为函数,则 net:: htons 将正常工作。

它出现在 -O1 或更高级别时,头文件公开了宏版本而不是函数。

可能的解决方案

using namespace net;  // Not recommended
#ifndef htons  // Recommended
using net::htnos;
#endif
extern "C" { // Add all declarations in global space
#include <arpa/inet.h>
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接