Difference between wait in stdlib.h and sys/wait - c

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.

Related

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.

There are multiple definitions of a variable but the linker does not generate errors on my machine

In my current project I'm initializing a window to draw on. I'm using a function pointer to deal with initialization from multiple platforms. So I really only want one instance of the window_init function pointer.
I noticed that I had forgotten to mark this function pointer as extern in my header file and defined it a second time in my C file to give it storage.
The header is included in multiple files so should, to my understanding, generate a linker error. I tested this on my laptop and it did in fact generate a linker error. Why is my desktop not generating errors/how can I find out? In both instances I used mingw64 with cmake in Clion to build, using -Wall -Wextra -pedantic -Werror.
So for clarity: my desktop builds fine, my laptop gives me linker errors. I expect linker errors for both machines and I want to find out why that doesn't happen.
The solution is of course to use extern and then it builds on both machines, however I want to know what is going on.
Here is a minimal example which also builds fine on my desktop while I'd expect it to fail:
window.h
#ifndef CEXTERNTETS_WINDOW_H
#define CEXTERNTETS_WINDOW_H
void window_functions_init();
void(*window_init)(); //This is the first definition and should be marked as extern to my understanding if I want to give it storage in my c file
#endif //CEXTERNTETS_WINDOW_H
window.c
#include "window.h"
#include <stdio.h>
void(*window_init)(); //This is the second definition
void window_init_implementation()
{
printf("window_init_implementation\n");
}
void window_functions_init()
{
window_init = &window_functions_init;
}
second include (I need to include window.h in multiple files so I added it here and added a function so that the compiler can't optimize it away)
#ifndef CEXTERNTETS_SECOND_INCLUDE_H
#define CEXTERNTETS_SECOND_INCLUDE_H
#include "window.h"
void doit()
{
printf("doit");
}
#endif //CEXTERNTETS_SECOND_INCLUDE_H
main.c
#include <stdio.h>
#include "window.h"
#include "second_include.h"
int main() {
window_functions_init();
window_init();
doit();
printf("Hello, World!\n");
return 0;
}
edit:
Was able to find this about -fno-common.
This is a common compiler extension popular in the Unix world. To disable the extension, use -fno-common.
-fno-common is not enabled in GCC before version 10 by default with any warning or standard option. This technically does not constitute a violation of the standard, because the standard list this as undefined behaviour. Undefined behaviour does not generally require diagnostic messages. An implementation is allowed to define behaviour that the standard leaves undefined.
This is however undesirable, and GCC 10 finally defaults to -fno-common.

Compiler warnings for execvpe function

I have a program written in c which uses the execvpe(3) function, and I've got a line set to include the requisite header file:
#include <unistd.h>
I compile this file with the following command...
gcc foo.c -o foo
...only to get the following warning:
warning: implicit declaration of function ‘execvpe’ [-Wimplicit-function-declaration]
I've encountered similar behavior with files that reference the pthread_create(3) function. The difference is obviously that whereas the pthread_create(3) man page clearly states that one should "Compile and link with -pthread", the man page for the exec(3) family of functions does not have any such instructions. Furthermore, I cannot find any reference in the manual or online to an analogous compiler flag for the exec(3) family.
I'd appreciate any information you have on this matter. If there is some flag I should be using at compile time, or if I am looking in entirely the wrong place for a solution, please let me know.
The man page here states that it is necessary to define the _GNU_SOURCE feature test macro to enable the function declaration:
#define _GNU_SOURCE
#include <unistd.h>
Interestingly however the link to unistd.h on the same man page takes you to an implementation that does not declare execvpe at all. You could check your system's unistd.h file to check that it is declared and is dependent on _GNU_SOURCE - that is to solve this an similar problems in the future - check the header content to see if it is even there and what macros it may depend on.
If it is not in the header file, then it is most probably also not in the library, but you could check as follows:
#include <unistd.h>
extern int execvpe(const char *file, char *const argv[], char *const envp[]);
which will satisfy the compiler, but if you then get a linker error, then the function is simply not included in the library in any case.

FreeBSD: Implicit declaration of getpagesize with _POSIX_C_SOURCE=200809L defined.

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.

Cannot interpret compiler warning

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

Resources