I am trying to use the open_memstream function in my C code. However I cannot seem to compile it. Minimal working example as follows:
#include <stdio.h>
int main(void) {
char *buf;
size_t sz;
FILE *stream = open_memstream(&buf, &sz);
putc('A', stream);
fclose(stream);
}
And I also use the following command to compile it:
gcc -std=c99 -o test test.c
After some research, I found that I need to define a macro before I include stdio.h. However the following example code was to no avail.
#define __USE_POSIX
#define __USE_XOPEN
#include <stdio.h>
The following compiler warnings are thrown; I assume the second warning is because of the first one.
test.c:7:17: warning: implicit declaration of function ‘open_memstream’ [-Wimplicit-function-declaration]
FILE *stream = open_memstream(&buf, &sz);
^
test.c:7:17: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
The __USE_* macros are internal to glibc's headers, and defining them yourself does not work. You should instead do one of the following:
Compile your program with -std=gnu11 instead of -std=c99 and don't define any special macros. This is the easiest change. Conveniently, -std=gnu11 is the default with newer versions of GCC.
If you have some concrete reason to want to select an old, strict conformance mode, but also you want POSIX extensions to C, then you can use the documented POSIX feature selection macros:
#define _XOPEN_SOURCE 700
or
#define _POSIX_C_SOURCE 200809L
These must be defined before including any standard headers. The difference is that _XOPEN_SOURCE requests an additional set of features (the "XSI" functions). See the Feature Test macros section of the glibc manual for more detail.
Note that if you need to request strict conformance mode from the library, using a -std=cXX option, then you almost certainly also want to use the -Wall and -Wpedantic options to enable strict conformance checking for the language. (You should use at least -Wall even if you don't need strict conformance checking.)
Related
Is there a way instruct the the compiler that:
The language is C90
The declarations of stdio.h are those of C99 (including snprintf)
With cc -std=c90 -Wall (on a source file using snprintf), an annoying warning is issued (sometimes, depending on the compiler/environment, with a confusing hint that stdio.h should be included, even if it already is), but the linker finds snprintf anyway. I understand what is happening, that is not the question.
Using strict c90 (language) and snprintf (library function) is technically well possible, but I do not know how to instruct the compiler accordingly. In other words, I would like to distinguish between language compliance and library compliance.
Remark: I assume that the language used in the C99 stdio.h header file is actually C90, and that it could thus be included by a C90 source file. Does anything prevent it?
I would prefer a solution with a generic include <stdio.h>, for the sake of portability.
Yes, though it's a bit of a weird thing to do.
You can define _ISOC99_SOURCE to signal that you want C99 functions to be defined.
Example:
#define _ISOC99_SOURCE
#include <features.h>
#include <stdio.h>
int main() {
char buf[10];
snprintf(buf, 4, "foo");
puts(buf);
return 0;
}
Compile it like so:
$ gcc -std=c90 -Wall test.c
$ ./a.out
foo
This will work in gcc 10.3.0 and clang 11.0.0. In terms of library compatibility, it has only been tested with glibc, and not musl or other versions of the standard library.
No.
A generic #include <stdio.h> for a C90 compiler needs not declare snprintf.
Before you argue that it's not a C90 compiler, keep in mind that you are requesting that it acts as one usng -std=c90. A compiler acting as a C90 compiler needs not do anything that a C90 compiler wouldn't do.
There is therefore no generic solution.
There may be compiler-specific solutions, including adding the following:
int snprintf( char * buffer, size_t bufsz, const char * format, ... );
THIS QUESTION IS NOT HOW TO REMOVE THE WARNING
I am writing a shell. I referred this source. I used the same headers (in the same order), as he did, in my code.
When compiling his code, I do not get any warnings for implicit declaration of getline. But when I compile mine, it does get thrown.
The man page suggests to use #define _GNU_SOURCE, and adding that removed the warning from my code.
So why was no warning thrown for the code in the blog, as he did not use #define _GNU_SOURCE?
Here is the minimal code (I copied all the headers as I mentioned above)
// #define _GNU_SOURCE
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
ssize_t bytes_read;
size_t input_buffer_size = 1024;
char *user_input = (char *)malloc(input_buffer_size * sizeof(char));
while (1)
{
printf("> ");
bytes_read = getline(&user_input, &input_buffer_size, stdin);
printf("%s\n", user_input);
}
return 0;
}
And here is the compilation process I used...
gcc -std=c11 -o bin/shell src/shell.c
Here is the error that I get if I leave the first line commented.
src/shell.c: In function ‘main’:
src/shell.c:18:18: warning: implicit declaration of function ‘getline’ [-Wimplicit-function-declaration]
18 | bytes_read = getline(&user_input, &input_buffer_size, stdin);
| ^~~~~~~
It appears that the person who wrote the tutorial you're referring to, did not supply any special compilation options when they were testing their code. I see only one compilation command anywhere on that page, and it is gcc -o main main.c. Thus, they got GCC's defaults, which, typically, make getline available on computers that have it.
You, however, used the compiler flag -std=c11 when you compiled your code. One of the effects of this flag is that GCC directs the C library's headers to declare only the functions, constants, variables, etc. that are specified by ISO C2011. (Depending on which C library you're using, this directive may or may not have any effect — but Ubuntu uses the GNU C library, which implements it thoroughly.) getline is not part of ISO C2011, so it is not declared and you get an "implicit declaration" diagnostic when you try to use it.
Use of the hyperconformant -std=cXX modes is almost always a mistake. There are exactly three differences between -std=cXX and -std=gnuXX and none of them is desirable in practice:
As discussed above, it directs the headers not to declare anything that's not part of the specified revision of ISO C. As you saw for yourself, this is almost never what you want when writing a nontrivial C program. It also has a nasty tendency to break library headers — both third-party headers and the C library's own headers — because they are rarely, if ever, tested in this mode.
It disables "system-specific predefined macros" that pollute the user namespace (e.g. linux, unix, arm). This is abstractly desirable but, like #1, has a nasty tendency to break library headers that are rarely, if ever, tested in this mode.
It enables trigraphs, which are a kludge to make C work with "national variants" of ASCII that are missing some punctuation. These are so rarely used and cause so much practical confusion that they were actually stripped out of C++ 2017 (not C 2017, though).
To compile your own code with a reasonably picky level of conformance diagnostics, but not risk breaking library headers, there is a better combination of options:
cc -std=gnuXX -g -Og -Wall -Wextra -Wpedantic -Wstrict-prototypes -Wwrite-strings
(Pick a suitable XX; if you have no reason to choose anything else, I'd go with 11.) You may or may not want to add a -D switch for one of the _xxx_SOURCE feature selection macros; explaining how those work and how to choose one is a whole question in itself.
Have a time date string I'd like to convert to a tm object. Google tells me the POSIX (but not the C) standard includes a function called strptime() that will do the job.
The man page says it's in <time.h> and that I need to include #define _XOPEN_SOURCE before I include the <time.h> file. Easy enough.
But I still get an implicit declaration warning from the compiler. I opened /usr/include/time.h and found the function declaration:
# ifdef __USE_XOPEN
/* Parse S according to FORMAT and store binary time information in TP.
The return value is a pointer to the first unparsed character in S. */
extern char *strptime (const char *__restrict __s,
const char *__restrict __fmt, struct tm *__tp)
__THROW;
#endif
So it looks like I need #define _USE_XOPEN instead.
Except that doesn't work either. The compiler still isn't seeing the declaration.
Any ideas. I'm using a relatively recent version of Linux (Mint) with gcc 5.4.0.
Converting comments into an answer.
To fix this, your options include using -std=gnu11 instead of -std=c11 on the GCC command line, or using #define _XOPEN_SOURCE 700 or equivalent (e.g. -D_XOPEN_SOURCE=700 on the command line). The 700 identifies POSIX 2008; 600 or 500 identify earlier versions of POSIX or X/Open.
In theory, you could also use _POSIX_C_SOURCE 200809L (see POSIX Compilation environment), but that doesn't expose everything that _XOPEN_SOURCE 700 exposes so it is usually better to use the latter.
Note that the POSIX specification of strptime() is annotated as an XSI extension, which means you must set _XOPEN_SOURCE; setting _POSIX_C_SOURCE alone is not sufficient.
Test code
This test code prints the address of the strptime function; it won't compile if strptime() is not declared.
#define _XOPEN_SOURCE 700
#include <time.h>
#include <stdio.h>
int main(void)
{
printf("%p\n", (void *)strptime);
return 0;
}
That should compile for you with gcc -std=c11 -Wall -c test-strptime.c. If you add -ansi to the options, you reset the standard back to C90. GCC 5.4.0 should default to C11 (effectively -std=gnu11) unless someone did something horrible in the build of GCC that you're using (which is unlikely).
Note that the compiler unsets and then sets __USE_XOPEN based on settings like _XOPEN_SOURCE and trying to set it manually doesn't work reliably.
Position matters
You must specify the #define _XOPEN_SOURCE 700 before the first system header is included (whether included directly or indirectly). If you include a system header before trying to set _XOPEN_SOURCE, the settings have been determined and your subsequent operations are effectively ignored. POSIX says (at the 'compilation environment' link already given):
In the compilation of an application that #defines a feature test macro specified by POSIX.1-2008, no header defined by POSIX.1-2008 shall be included prior to the definition of the feature test macro. This restriction also applies to any implementation-provided header in which these feature test macros are used. If the definition of the macro does not precede the #include, the result is undefined.
One common undefined result is that your attempt to set/change the POSIX version is completely ignored.
I am currently porting some OS related function of a software project from Linux to FreeBSD. Thereby, I recognized the following problem using getpagesize if _POSIX_C_SOURCE=200809Lis defined on FreeBSD 10.1.
I created a small test program
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int i = getpagesize();
return 0;
}
If I compile is using
cc test.c -o test
it compiles without any warnings. But if I define _POSIX_C_SOURCE=200809L (result of the proper POSIX definition of getline function which I need in other parts of the code) I get:
cc test.c -D_POSIX_C_SOURCE=200809L
test.c:5:10: warning: implicit declaration of function 'getpagesize' is invalid in C99 [-Wimplicit-function-declaration]
int i = getpagesize();
^
Although I included unistd.h as stated in the manpage of getpagesize. How can I make the code compiling without warnings with still defined _POSIX_C_SOURCE?
(1) The _POSIX_C_SOURCE is a wrong define. You need the _XOPEN_SOURCE. For example:
cc -D_XOPEN_SOURCE=700 test.c
or
cc -D_XOPEN_SOURCE=600 test.c
The 600 and 700 signify version of the Single Unix Specification (SUS for short, aka Open Group Specification, aka POSIX) your application expects from the system library. See here for the SUSv7.
(2) BUT. That might still not work, because the getpagesize() is a BSD-specific function, which actually might be hidden if you try to compile the file in the POSIX-compliance mode.
Normally you need nothing special to get access to the BSD functions on a BSD system, but portable way is to provide the _BSD_SOURCE define.
The more portable, POSIX-compliant way to get the page size is sysconf(_SC_PAGE_SIZE) function. FreeBSD man page.
P.S. Do not have a BSD at hand to test it.
My compiler (gcc) throws warnings (not errors!) on the line which declares fp:
int fd = open("filename.dat", O_RDONLY);
FILE* fp = fdopen(fd, "r"); // get a file pointer fp from the file descriptor fd
These are the warnings:
main.c: In function ‘main’:
main.c:606: warning: implicit declaration of function ‘fdopen’
main.c:606: warning: initialization makes pointer from integer without a cast
I do not understand these warnings since the return value of fopen is a FILE*. What is the mistake I am making here?
EDIT: I am including stdio.h (and I am also on Linux).
Short answer: use -std=gnu99 when compiling, the usual standard is non-POSIX and does not have fdopen.
warning: implicit declaration of function ‘fdopen’
Means you have forgot to include the header file which the declaration of fdopen() resides in. Then an implicit declaration by the compiler occurs - and that means the return value of the unknown function will be assumed to be int - thus the second warning. You have to write
#include <stdio.h>
Edit: if you properly include stdio.h, then fdopen() might not be available on the system you're targeting. Are you on Windows? This function is POSIX-only.
Edit 2: Sorry, I really should have perceived this. C99 means the ANSI C99 standard - and standard C doesn't force the concept of file descriptors in order to support non-POSIX systems, so it provides fopen() only. fdopen() is related to file descriptors, so it's POSIX-only, so it's not part of standard C99. If you use the -std=gnu99 switch for GCC, it gets rid of the standard's restrictions and lets in the POSIX and GNU-only extensions, essentially fixing your problem.
#define _XOPEN_SOURCE 600
#include <stdio.h>
This conforms perfectly with strict c99
gcc -std=c99 -pedantic -Wall -Wextra -Werror
You are not including #include <stdio.h> in C the compiler therefore "guesses" the declaration of the function you're trying to call. (Taking the parameters you've based and using int as return value). Usually you don't want such guesses therefore the compiler warns you.
Solution: Add proper #includes.
The fdopen function is not part of the C standard and is not available as part of the standard headers if you compile in standard C mode. So you either need to use -std=gnu99 instead of -std=c99 to compile your source or declare the function yourself.
There's a good explanation for the compiler's diagnostic in #H2CO3's answer, so let's only look on the why of things: if you're using glibc (and you probably are), certain POSIX functions may require specific feature test macros to show up.
In particular, you may need to put the following line:
#define _POSIX_SOURCE
// or #define _XOPEN_SOURCE
before
#include <stdio.h>
Certain compilers (such as gcc) also have command line options to the same effect (all the gnu* standards options in gcc).