Cannot interpret compiler warning - c

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).

Related

Using snprintf with C90

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, ... );

implicit declaration of function ‘getline’ warning thrown in one code, but not in another

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.

Use open_memstream with c99

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.)

Difference between wait in stdlib.h and sys/wait

I'm pretty sure there's such question, but I can't find it :\ Anyway, here's the issue:
What is the difference between wait in stdlib.h and sys/wait.h o.O ?
In details - I just encountered this problem and I could't compile a simple C program. I isolated the problem and here's what I got:
#include <stdlib.h>
//#include <sys/wait.h>
int main()
{
int status;
wait( &status );
return 0;
}
If stdlib.h is included, I got:
$ gcc asd.cpp
asd.cpp: In function ‘int main()’:
asd.cpp:9:16: error: conflicting declaration ‘wait& status’
asd.cpp:8:6: error: ‘status’ has a previous declaration as ‘int status’
What declaration ? O.o What is wait here, that conflicts with int status?
I found a thread in the net, where replacing stdlib.h with sys/wait.h solves the problem, but why is that and what is the difference?
EDIT: Thanks to sidyll's comment, I changed the file extention - from .cpp to .c and it worked! I'm shocked :) How is this so different? And still the same question - what is the different between those two wait-s ?
The difference is that the wait() in <sys/wait.h> is the one you should use.
From the wait(3) man page:
SYNOPSIS
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
The wait function isn't defined by the ISO C standard, so a conforming C implementation isn't allowed to declare it in <stdlib.h> (because it's legal for a program to use the name wait for its own purposes). gcc with glibc apparently does so in its default non-conforming mode, but if you invoke it with gcc -ansi -pedantic or gcc -std=c99 -pedantic, it doesn't recognize the function name wait or the type pid_t.
I did gcc -E wait.cpp to dump the actual preprocessor expansions that take place. What I found was that on linux, the header /usr/include/bits/waitstatus.h is included which pulls in a union wait { ... } but the function wait() from sys/wait.h is never pulled in. The same thing happens with the c compilation, but the for whatever reason the compiler does not complain in that case.
To prove this to yourself, you can change your main to declare the wait as a variable rather than a function call, and the compiler will not complain:
int main() {
int status;
wait w;
return 0;
}
Note that GCC stands for GNU Compiler Collection, not GNU C Compiler (as many
other tools which were prefixed with a g). It's not a C-only compiler. And
many languages are detected by file extensions. Adam Rosenfield is partialy
correct in his comment. Yes, g++ will add the C++ library in the linker phase,
but that's not the unique difference (more on this later).
To explain how changing the extension solved it, please take a look in this text
straight from GCC's manual:
Compiling C++ Programs
C++ source files conventionally use one of the suffixes.C, .cc, .cpp,
.CPP, .c++, .cp,or.cxx;C++ header files often use.hhor.H;and
preprocessed C++ files use the suffix .ii. GCC recognizes files with
these names and compiles them as C++ programs even if you call the
compiler the same way as for compiling C programs (usually with the
namegcc).
So, "GCC regocnizes files with these names" and your program was being compiled
as C++ source. I guess that C++ has some special use of &, which I can't tell
exactly (I don't know C++). Hence the error.
Now, regarding the difference between g++ and gcc, continue with the next
paragraph:
However, the use ofgccdoes not add the C++ library.g++is a program
that calls GCC and treats.c, .hand.ifiles as C++ source files
instead of C source files unless-xis used, and automatically
specifies linking against the C++ library. This program is also useful
when precompiling a C header file with a.hextension for use in C++
compilations. On many systems,g++is also installed with the name
c++.
On the real question: there aren't two waits here in my system (Darwin 11), only
the standard syscall. Check if what Kevin said isn't happening. It's the same,
stdlib.h includes sys/wait.h:
#include <_types.h>
#if !defined(_ANSI_SOURCE)
#include <sys/wait.h>
#if (!defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE))
#include <alloca.h>
#endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
#endif /* !_ANSI_SOURCE */
Check your header.

How could my code compile correctly without necessary headers?

I use the functions fork(),exec()...
But how can this program be compiled without including some extra headers (like sys/types.h, sys/wait.h).
I use ubuntu 10.04 with gcc version 4.4.3
#include <stdio.h>
#include <stdlib.h>
int main()
{
pid_t pid;
printf("before fork\n");
pid = fork();
if(pid == 0)
{
/*child*/
if(execvp("./cpuid", NULL))
{
printf("error\n");
exit(0);
}
}
else
{
if(wait(NULL) != -1)
{
printf("ok\n");
}
}
return 0;
}
In classic "ANSI" C, if you call a function without declaring it the compiler behaves as if the function was implicitly declared to take a fixed-but-unspecified number of arguments and return int. So your code acts as if fork() and execvp() were declared thus:
int fork();
int execvp();
Since execvp() takes a fixed number of arguments and returns int, this declaration is compatible. fork() also takes a fixed number of arguments, but returns pid_t; however since pid_t and int are equivalent types on most Linux architectures, this declaration is effectively compatible too.
The actual definitions of these functions are in the C standard library, which is linked by default, so the definition is available at link time and thus the code works.
As Keith Thompson notes, this language feature was dropped in the C99 revision of the C language standard, and compilers invoked in C99 or C11 mode must at least issue a warning when a function is called without being explicitly declared.
exec and fork are declared in unistd.h, which is most likely included in one if stdio.h or stdlib.h which you explicitly specified in your code. "wait" is from sys/wait.h though... Try invoking gcc with -c -E to generate a preprocessed output and see where the functions' declarations come from.
caf's answer is only partially correct.
Under the rules specified by the C89/C90 standard (commonly called "ANSI C"), a call to a function with no visible declaration is legal. The compiler assumes that the function returns an int result and takes arguments of the (promoted) type(s) given in the call. If the call is not consistent with the function definition, the behavior is undefined. For such a call, it's entirely the programmer's responsibility to get the call right; the compiler likely will not tell you if you make a mistake.
The 1999 ISO C standard dropped this "implicit int" rule, and made a call to an undeclared function a constraint violation, requiring a diagnostic. (The diagnostic may be a non-fatal warning, or it can cause compilation to fail.) Once the diagnostic has been printed, if the compiler creates an executable, its behavior is undefined.
Unfortunately, many compilers still don't enforce modern C rules by default. Most of them can be made to do so with appropriate compile-time options.
For gcc in particular, you can compile with
gcc -std=c99 -pedantic
or
gcc -std=c11 -pedantic
(The latter didn't exist yet when caf's answer was written.) Or, if you also want to use gcc-specific extensions, you can use -std=gnu99 or -std=gnu11. The default is currently -std=gnu89. This will likely be changed to -std=gnu11 in a future release of gcc.
gcc-compatible compilers like clang will generally follow the same rules. For other compilers, you'll have to consult their documentation to find out how to persuade them to enforce modern C rules. (Microsoft's C compiler has very incomplete support for standards later than C90.)

Resources