Error "'fdopen' was not declared" found with g++ 4 that compiled with g++3
Asked Answered
G

2

6

I have code that compiled happily with g++ version 3.something. I then wanted to build some other code that had C++11 symbols in it so I upgraded to g++ 4.7. Now my original code doesn't build. I get the error:

'fdopen' was not declared in this scope

According to the man page, fdopen() is declared in stdio.h which I am including. I'm not sure it is relevant, but I am working in a Cygwin environment. The exact version of g++ I am using is version 4.7.2 provided by Cygwin.

I have not changed this code since I switched compiler and I can definitely confirm that it built and my test code ran and passed with the previous compiler.

As requested, example code to demonstrate the problem:

#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
Gaynell answered 11/4, 2013 at 8:28 Comment(2)
Without seeing some code it is hard to know for sure, if you can condense it down to a small sample that still shows the problem that would help.Belomancy
Code added. I wrote it from scratch. My apologies, I thought that from the problem description, the above code could be assumed, if required. Basically fdopen is declared in <stdio.h> according to the man page and compiling with g++ 3 the function is found and with g++4 it isn't. So just put fdopen() in some code and compile to get the same problem.Gaynell
G
4

The problem comes from -std=c++11. The fdopen() function is not in ANSI C (only in the POSIX standard), and compiling with -std=c++11 option implies defining __STRICT_ANSI__, which excludes several functions from stdio.h. By the way, in C++ programs, you should normally include <cstdio> instead of <stdio.h>, see here: stdio.h not standard in C++?.

If you need to use fdopen(), you might want to remove the -std=c++11 option when compiling. Another possible soltion, although not really elegant, can be to use this in your source code:

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

(which is intended to work with and without the -std=c++11 option).

Gigantism answered 11/4, 2013 at 9:51 Comment(2)
Not good. I need the c++11 flag because someone else working on the project is using C++11 types. I need fdopen because I need to open the file with flags and then convert it to a file pointer. You can't open a file as exclusive create using fopen(). Looks like I'm screwed.Gaynell
You can try with this: #undef __STRICT_ANSI__ #include <cstdio> #define __STRICT_ANSI__ It is not very elegant, but works... will add that to the answer too, in case it might help somebody.Gigantism
T
11

Whatever you do, please don't mess with the __STRICT_ANSI__ flag. That symbol is controlled by GCC. You should let GCC define it and leave it alone.

What you are really looking for is the _POSIX_C_SOURCE feature test macro. You see, fdopen is not defined by the C language standard. When you tell GCC that you are writing a C++11 program, then GCC goes into "strict" mode where it tries to not define any functions that are not defined by the language. This is to avoid name collisions with your own code. For instance, a valid C++11 program is free to define its own function named fdopen since fdopen is not a reserved identifier in the language.

But fdopen is defined by POSIX, which is a standard that includes, but is separate from, the C language standard. When writing an application that uses POSIX functions, like fdopen, you must tell the system that you intend to write a POSIX application so that it knows that it should make functions defined by POSIX available to your program. This is where the _POSIX_C_SOURCE feature test macro comes in. At the top of every source file, before inclusion of any header, define this macro to the appropriate value. For instance:

#define _POSIX_C_SOURCE 200112L

The value you should use in the definition depends on which version of POSIX you are targeting. If you are unsure about which version you want to target, you can just target the same version that your host system is compliant with. You can determine this by running getconf from a shell:

$ getconf _POSIX_VERSION
200809L
$ _

Here, my system tells me it is compliant with POSIX version 200809L (i.e. POSIX.1-2008). I can #define _POSIX_C_SOURCE 200809L in my source code and be confident that all standard features supported by my system will be made available to me.

Topmast answered 11/4, 2013 at 12:14 Comment(3)
@Ale: That's because the Newlib developers (who write the C library used by Cygwin and MinGW) don't understand the purpose of the POSIX feature test macros, either. This has been a problem with Newlib for years, even though it has been pointed out to them numerous times (for an amusing example, see cygwin.com/ml/cygwin/2011-10/msg00145.html; the whole thread is great!) They are only now getting around to gradually fixing their header files. Unfortunately, they still have not fixed <stdio.h> where fdopen is declared.Topmast
@Ale: Correction: MinGW doesn't use Newlib. But their header files have the same mistake (probably due to their shared ancestry with Cygwin; or maybe it's just that common for programmers to not understand the POSIX feature test macros). In any case, MinGW is a poor example since the MinGW developers claim they are not developing a POSIX-compliant system. It's kind of pointless to be testing POSIX features (like fdopen) on a system that isn't, and doesn't want to be, POSIX-compliant.Topmast
Thanks for the answer. An easier option may be to use -D_POSIX_C_SOURCE=200809 compiler flag.Gavotte
G
4

The problem comes from -std=c++11. The fdopen() function is not in ANSI C (only in the POSIX standard), and compiling with -std=c++11 option implies defining __STRICT_ANSI__, which excludes several functions from stdio.h. By the way, in C++ programs, you should normally include <cstdio> instead of <stdio.h>, see here: stdio.h not standard in C++?.

If you need to use fdopen(), you might want to remove the -std=c++11 option when compiling. Another possible soltion, although not really elegant, can be to use this in your source code:

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

(which is intended to work with and without the -std=c++11 option).

Gigantism answered 11/4, 2013 at 9:51 Comment(2)
Not good. I need the c++11 flag because someone else working on the project is using C++11 types. I need fdopen because I need to open the file with flags and then convert it to a file pointer. You can't open a file as exclusive create using fopen(). Looks like I'm screwed.Gaynell
You can try with this: #undef __STRICT_ANSI__ #include <cstdio> #define __STRICT_ANSI__ It is not very elegant, but works... will add that to the answer too, in case it might help somebody.Gigantism

© 2022 - 2024 — McMap. All rights reserved.