6

我有用 g++ 版本 3.something 愉快地编译的代码。然后我想构建一些其他包含 C++11 符号的代码,所以我升级到 g++ 4.7。现在我的原始代码没有构建。我得到错误:

'fdopen' 未在此范围内声明

根据手册页, fdopen() 在我包括在内的 stdio.h 中声明。我不确定它是否相关,但我在 Cygwin 环境中工作。我使用的 g++ 的确切版本是 Cygwin 提供的 4.7.2 版本。

自从我切换编译器以来,我没有更改此代码,我可以肯定地确认它已构建并且我的测试代码运行并通过了以前的编译器。

根据要求,演示问题的示例代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char **argv)
{
    int   fd;
    FILE *fp;

    fd = open("test.txt", (O_WRONLY | O_CREAT | O_EXCL), S_IRWXU);
    if(0 < fd)
    {
        fp = fdopen(fd, "wb");

        fprintf(fp, "Testing...\n");
        fclose(fp);
    }

    return 0;
}


# g++ -std=c++11 -o test test.cpp
test.cpp: In function 'int main(int, char**)':
test.cpp:14:29: error: 'fdopen' was not declared in this scope
4

2 回答 2

11

无论你做什么,请不要乱用__STRICT_ANSI__旗帜。该符号由 GCC 控制。您应该让 GCC 定义它并不管它。

您真正需要的是_POSIX_C_SOURCE功能测试宏。你看,fdopen不是由C语言标准定义的。当您告诉 GCC 您正在编写 C++11 程序时,GCC 会进入“严格”模式,在该模式下,它会尝试不定义该语言未定义的任何函数。这是为了避免名称与您自己的代码冲突。例如,一个有效的 C++11 程序可以自由定义自己的函数fdopen,因为fdopen它不是语言中的保留标识符。

Butfdopen POSIX 定义,POSIX 是一个包含但独立于 C 语言标准的标准。在编写使用 POSIX 函数的应用程序时,例如fdopen您必须告诉系统您打算编写一个 POSIX 应用程序,以便它知道它应该使 POSIX 定义的函数对您的程序可用。这是_POSIX_C_SOURCE功能测试宏的用武之地。在每个源文件的顶部,在包含任何标题之前,将此宏定义为适当的值。例如:

#define _POSIX_C_SOURCE 200112L

您应该在定义中使用的值取决于您所针对的 POSIX 版本。如果您不确定要定位哪个版本,您可以只定位与您的主机系统兼容的相同版本。您可以通过getconf从 shell 运行来确定这一点:

$ getconf _POSIX_VERSION
200809L
$ _

在这里,我的系统告诉我它符合 POSIX 版本200809L(即 POSIX.1-2008)。我可以#define _POSIX_C_SOURCE 200809L在我的源代码中并确信我的系统支持的所有标准功能都将提供给我。

于 2013-04-11T12:14:58.660 回答
4

问题来自-std=c++11. 该fdopen()函数不在 ANSI C 中(仅在 POSIX 标准中),使用-std=c++11选项编译意味着定义__STRICT_ANSI__,它排除了stdio.h. 顺便说一句,在 C++ 程序中,您通常应该包含<cstdio>而不是<stdio.h>,请参见此处:stdio.h not standard in C++? .

如果您需要使用fdopen(),您可能希望-std=c++11在编译时删除该选项。另一种可能的解决方案虽然不是很优雅,但可以在源代码中使用它:

#ifdef __STRICT_ANSI__
#undef __STRICT_ANSI__
#include <cstdio>
#define __STRICT_ANSI__
#else
#include <cstdio>
#endif

(旨在使用和不使用该-std=c++11选项)。

于 2013-04-11T09:51:35.987 回答