我正在研究将一些代码从较旧的 C++ 移植到更现代的 C++ 版本(例如 C++ 11 或更高版本)。然后我注意到当我添加编译器标志 -std=c++11
最简单的 MVCE 示例。我在使用最新的 Cygwin(实际上是今天安装的)。 g++ --version
表示版本 7.3.0。
将以下源文件精简到几乎没有,但足以说明我将要解释的问题。
#include <stdio.h>
#include <sys/socket.h>
#include <netdb.h>
int some_networking_code()
{
addrinfo* addr = NULL;
int flags = AI_NUMERICHOST;
return 0;
}
在全新安装的 Cygwin 上,以下命令工作正常:
g++ foo.cpp -c
但现在切换到使用 C++11 进行编译。
g++ foo.cpp -c -std=c++11
编译器的输出结果是:
foo.cpp: In function ‘int some_networking_code()’:
foo.cpp:8:4: error: ‘addrinfo’ was not declared in this scope
addrinfo* addr = NULL;
^~~~~~~~
foo.cpp:8:4: note: suggested alternative: ‘addr_t’
addrinfo* addr = NULL;
^~~~~~~~
addr_t
foo.cpp:8:14: error: ‘addr’ was not declared in this scope
addrinfo* addr = NULL;
^~~~
foo.cpp:8:14: note: suggested alternative: ‘addr_t’
addrinfo* addr = NULL;
^~~~
addr_t
foo.cpp:9:16: error: ‘AI_NUMERICHOST’ was not declared in this scope
int flags = AI_NUMERICHOST;
^~~~~~~~~~~~~~
调试它,我看了一下 /usr/include/netdb.h
,我看到 addrinfo
的定义需要一个名为 __POSIX_VISIBLE< 的宏/strong> 大于或等于 200112
。 AI_NUMERICONLY 的定义包含在一个类似的 block 中。
#if __POSIX_VISIBLE >= 200112 && !defined(__INSIDE_CYGWIN_NET__)
struct addrinfo {
int ai_flags; /* input flags */
… <deleted for brevity>
#endif
使用 -dM -E
开关,我们可以询问编译器它正在引入哪些宏并过滤到 POSIX_VISIBLE
$ g++ foo.cpp -c -dM -E | grep POSIX_VIS
#define __POSIX_VISIBLE 200809
好的,对于传统的 C++ 来说这看起来是正确的。让我们检查一下 C++11 构建:
$ g++ foo.cpp -c -std=c++11 -dM -E | grep POSIX_VIS
#define __POSIX_VISIBLE 0
__POSIX_VISIBLE
被定义为 0。这就解释了为什么我们会出现上述错误。
POSIX_VISIBLE
似乎是由位于 /usr/include/sys/features.h
的头文件根据其他定义的宏定义的。但这正是我开始感到困惑的地方。
这是 Cygwin 发行版或其头文件中的错误吗?编译器的构建方式?或者是其他东西?不会影响在 Linux、Mac、BSD 和其他任何地方构建的适当解决方法是什么?
最佳答案
我在 Cygwin mailing list 上进行了讨论.我曾假设在命令行上不指定 -std
会限制我的构建,使其无法访问现代 C++ 功能。并且指定 -std=c++11
或更高版本将启用这些更新的功能。这其实是不正确的。较新版本的 g++ 默认为较新的内容:
$ g++ -c foo.cpp -dM -E | grep cplus
#define __cplusplus 201402L
并且使用 -std
不仅限制了编译器功能行为,而且还禁用了 GNU 内置定义。当未定义 GNU_SOURCE 时,Cygwin header 将隐藏多个 POSIX 函数,包括 getaddrinfo
。我不确定我是否同意这种配置,但这就是它在 Cygwin 上的工作方式。避免 -std
是更好的解决方法。
更新
虽然避免使用 -std
是一个很好的解决方法,但 6.0 之前的 g++ 早期版本默认为 C++ 98,除非使用 -std
。而且仍然有很多人在使用 6.0 之前的 g++ 版本。我调查了很多 Makefile hack 来嗅探 C++ 11 支持或编译器版本,以便有条件地使用 -std=c++11
,但没有一个是漂亮的。似乎对 g++、Cygwin 和 Clang 通用的解决方法是使用 -std=gnu++11
。
即:
g++ foo.cpp -c -std=gnu++11
关于c++ - 在 Cygwin 上使用 -std=c++11 编译会隐藏可用的系统调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52157480/