Standard functions in C99 being called "Implicit declarations" - c

I have a C program that I am running on my MacOS terminal. All command line tools and GCC compiler have been installed. However for using functions like getpid() or execv() it gives the following error:
execv-test.c:7:35: error: implicit declaration of function 'getpid' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
printf("Pid before execv: %d\n", getpid());
^
execv-test.c:8:2: error: implicit declaration of function 'execv' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
execv("print",NULL);
^
2 errors generated.
The code:
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
printf("The game is never over, John. But there may be some new players now.\n");
printf("Pid before execv: %d\n", getpid());
execv("print",NULL);
printf("Returned from execv call.\n");
return 0;
}
The following Stack Overflow exchange suggested that I write helper functions for the ones that were taken as implicit declarations. However, I am not sure you could do the same with getpid() or execv(). What should I do to make sure this doesn't happen?
PLEASE NOTE: "print" is just another helper file that is supposed to be run once execv() is called.

Note that you are using system calls that are defined in the unistd.h header file. Therefore calling them without including the std library #include <unistd.h> amounts to "implicit declaration" = "calling a function without defining it first".

Related

How do calls to the execvp system call work?

I was doing a research into the contents of another StackOverflow question and I thought it was a good time to brush up my knowledge of unix system calls.
While experimenting with execvp (WITHOUT fork on purpose) I ran into something that confuses me
I wrote 4 test programs
Program 1
#include <stdio.h>
int main() {
//printf("Doge\n");
execvp("ls");
printf("Foo\n");
return 0;
}
The program works as expected, the contents of the directory are printed and the Foo print statement is not
Program 2
However when I uncomment the first print statement and have the program be this
#include <stdio.h>
int main() {
printf("Doge\n");
execvp("ls");
printf("Foo\n");
return 0;
}
execvp returns a -1 and both print statements are issued. why?
Program 3
I vaguely remember having to use unistd.h when experimenting with unix system calls from college.
So I included it, but not execvp has a different signature and it needed some more args than just the name of the program. So I did this
#include <stdio.h>
#include <unistd.h>
int main() {
printf("Doge\n");
char *const parmList[] = {"ls", NULL};
execvp("ls", parmList);
printf("Foo\n");
return 0;
}
And this works. This has confused me. Why did exec work in the first program?
I also used This as a reference to the system calls.
Finally I wrote
Program 4
#include <stdio.h>
//#include <unistd.h>
int main() {
printf("Doge\n");
char *const parmList[] = {"ls", NULL};
execvp("ls", parmList);
printf("Foo\n");
return 0;
}
Which also works as expected.
Can someone explain what's going on?
With this snippet
#include <stdio.h>
int main() {
execvp("ls");
printf("Foo\n");
return 0;
}
you're invoking undefined behaviour. You're not providing the prototype for execvp which requires an argument list (null terminated) as a second parameter.
Using gcc without any warning option silently uses execvp as implicitly declared, and doesn't check parameters. It just calls the function. The function then looks for a second parameter and encounters... whatever is left of the call stack (or registers, depending on call conventions), that's why a previous printf call can change the behaviour.
Using gcc -Wall gives the following warning:
test.c:5:9: warning: implicit declaration of function 'execvp' [-Wimplicit-function-declaration]
execvp("ls");
Including the proper include (#include <unistd.h>) leads to:
test.c:6:9: error: too few arguments to function 'execvp'
execvp("ls");
^~~~~~
That's why you've got strange behaviour. Don't look further. Use execvp with 2 arguments, period. In your case "Program 3" is the way to go, and always set warning level to the maximum, if possible (gcc and clang: -Wall -Wextra -pedantic -Werror)

FILE * ..=stdout : Error initializer element is not constant

My C code was as following:
[Linux:/si/usr/hrl]vi test.c
#include <stdio.h>
FILE * hw = stdout;
int main(void)
{
return 0;
}
When I compile on SUSE , it make the error like that:
[Linux:/si/usr/hrl]cc test.c -o test
test.c:3: error: initializer element is not constant
I have a look for the header file stdio.h and find that stdout seems to have be defined as a constant. So why the error produce?By the way, I compile the same code on AIX ,it results of success.
The standard does not require stdin, stdout and stderr to be constants.
The draft n1256 for C99 says in 7.19.1 Input/output <stdio.h>
The header declares ...
...
TMP_MAX
which expands to an integer constant expression ...
stderr
stdin
stdout
which are expressions of type ‘‘pointer to FILE’’ ...
(emphasize mine)
It is explicitely stated that some other values are constant, whereas nothing is said for stdin, stdout and stderr
So you must put initialization in main:
#include <stdio.h>
FILE * hw;
int main(void)
{
hw = stdout;
...
return 0;
}
In AIX standard library, stdout happens to be a constant, but it is just an implementation detail and you cannot rely on that, as it could break in any newer version.
But you should not rely either on stdout being a variable (nor even a lvalue), because it is also an implementation detail in GCC library.
If you cannot change much of your code, and just need a GCC hack to make it compilable, you could try to use the gcc constructor attribute extension.
Extract from gcc documentation
6.31 Declaring Attributes of Functions
In GNU C, you declare certain things about functions called in your program which help the compiler optimize function calls and check your code more carefully.
The keyword __attribute__ allows you to specify special attributes when making a declaration. This keyword is followed by an attribute specification inside double parentheses. The following attributes are currently defined for functions on all targets: ... ,constructor, ...
...
The constructor attribute causes the function to be called automatically before execution enters main () ...
So you could use:
#include <stdio.h>
FILE * hw;
void initHw(void) __attribute__((constructor)) {
hw = stdout;
}
int main(void)
{
return 0;
}
But BEWARE: it is a gcc extension, meaning that your code is not correct C.

Compilation Error in i/o redirection in C program in linux

I'm trying to make a simple I/O redirection(ls to sort)(ls|sort>f1) and then my next step is to direct the output of sort to a file in C but when compiling gcc is giving following error..plz help me :)
Code
#include<stdio.h>
#include<fcntl.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
int a,b,c,d,pfd[2],kk,i,j;
FILE *fp;
i=fork();
if(i==0)
{
pipe(pfd);
j=fork();
if(j==0)
{
close(1);
dup(pfd[1]);
close(pfd[0]);
close(pfd[1]);
excel("/bin/ls","/ls",0);
}
else
{
close(0);
dup(pfd[0]);
close(pfd[0]);
close(pfd[1]);
/*close(1);
kk=open(f.txt,O_WRONLY);
dup(kk);
*/
excel("/usr/bin/sort","/sort",0);
}
}
else
wait();
/*char k[100],pp[100],ll[]="/bin/";
printf("Enter the cmd to execut");
scanf("%s",k);
strcpy(pp,k);
strcat(ll,k);
printf("%s",ll);
system(ll);*/
return 0;
}
Error:
/tmp/cc6wIvoJ.o:
In function **main**:
j.c:(.text+0x81): undefined reference to **excel**
j.c:(.text+0xcf): undefined reference to **excel**
collect2: error: ld returned 1 exit status
There are some bogus answers here which I can't comment on since I don't have '50 reputation' points. Hence an entirely new reply instead.
As correctly noted by people you obviously have a typo, you want execl instead of excel.
However, people claim that execl is a system call. IT IS NOT. It's a convenience function in your libc. Syscall which is executed at the end of the day is execve, which you can confirm by e.g. using strace.
There are several issues with your code, do you have warnings enabled when you compile? -Wall -Wextra to gcc will definitely help out.
Example issues:
- wait() takes an argument, and you would be warned about this if only you had proper header files included
- missing error checking (fork, pipe, wait)
In general your coding style will lead you to trouble.
Always include relevant headers (to be found in manpages) and check return values.
There isn't a system call called excel. Hence you are getting undefined error. Try using one of the exec() family of calls like execl. -
http://linux.die.net/man/3/execl
Its execl not excel . execl is the call you are looking for.

Whats wrong with this signal example?

My instructor posted this program to give an example of signals, I tried to compile it but i got three warnings:
Buzzoff.c:17:5: warning: implicit declaration of function 'alarm' is invalid in
C99 [-Wimplicit-function-declaration]
alarm(2);
^
Buzzoff.c:21:5: warning: implicitly declaring library function 'exit' with type
'void (int) __attribute__((noreturn))'
exit(-1);
^
Buzzoff.c:21:5: note: please include the header <stdlib.h> or explicitly provide
a declaration for 'exit'
Buzzoff.c:33:5: warning: implicit declaration of function 'pause' is invalid in
C99 [-Wimplicit-function-declaration]
pause();
^
3 warnings generated.
I still don't understand how signals work and cant seem to figure out whats exactly wrong with this program. could someone help me understand whats wrong and how to fix it?
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void handler(int s)
{
printf("Please wake up 1730 !!!!!!! \n");
}
int cnt = 0;
void boom(int s)
{
if (cnt<5) {
printf("tick\n");
cnt = cnt+1;
alarm(2);
}
else {
printf("Boom!\n");
exit(-1);
}
}
int main()
{
signal(SIGINT, handler);
signal(SIGALRM, boom);
alarm(5);
while(1) {
printf("...ZZZZzzzzz...\n");
pause();
}
}
Besides the fact that signal is deprecated and sigaction is its replacement, there's nothing wrong with the code. The only problem is that there are some files that should have been included but they are not which is what the compiler is trying to tell you.
However, the code contains the correct header files! alarm and pause are defined in unistd.h and exit is defined in stdlib.h, both of which are included. If your compiler is complaining about those files, there's something wrong with the compiler, or the installation of the standard libraries.
Possible problems could be a bad OS (read Windows), bad installation (by a crazy Linux distribution) or something you did wrong yourself, for example move some files you shouldn't have. Not understanding alarm and pause hints at a non-POSIX operating system such as Windows. However, not understanding exit hints at something very wrong with the compiler itself.
Can you also post the command you execute to compile the code? You don't happen to be including -nostdinc for some reason, do you?
on Mac and BSD simply give a strike to terminal:
NAME
alarm -- set signal timer alarm
LIBRARY
Standard C Library (libc, -lc)
SYNOPSIS
#include <unistd.h>
so You should simply include unistd.h, and You got it.
I tried on my BigSur on terminal:
ingconti#MBP-32GB-BigSur signal % ./stackoverflow
...ZZZZzzzzz...
tick
...ZZZZzzzzz...
tick
...ZZZZzzzzz...
tick
...ZZZZzzzzz...
tick
...ZZZZzzzzz...
tick
...ZZZZzzzzz...
Boom!
so it WORKS on Mac!

How to run this threads example?

I'm trying the code from Tanenbaum's 3e "Modern Operating Systems" and I get compiler errors and warnings:
$ LANG=en_US.UTF-8 cc thread.c
thread.c: In function ‘main’:
thread.c:19:63: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
thread.c:25:1: warning: passing argument 1 of ‘exit’ makes integer from pointer without a cast [enabled by default]
/usr/include/stdlib.h:544:13: note: expected ‘int’ but argument is of type ‘void *’
/tmp/ccqxmMgE.o: In function `main':
thread.c:(.text+0x57): undefined reference to `pthread_create'
collect2: ld returned 1 exit status
This is the code I'm trying
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NUMBER_OF_THREADS 10
void *print_hello_world(void *tid)
{
//printf("Hello World. Greetings from thread %d0", tid);
pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
pthread_t threads[NUMBER_OF_THREADS];
int status, i;
for(i=0; i<NUMBER_OF_THREADS; i++) {
//printf("Main here creating thread %d0", i);
status = pthread_create(&threads[i], NULL, print_hello_world, (void *)i);
if (status != 0) {
//printf("Oops. pthread_create returned error code %d0", status);
exit(-1);
}
}
exit(NULL);
}
Can you help me improve the state of the code so that it will run? There appears to be some errata since the exact code from the book doesn't compile. Thanks
Please link to pthread library, by specifying -lpthread option to your linker.
Also, you should be using pthread_join to wait for all the created threads to complete.
$gcc thread.c -lpthread
This is to link the pthread shared library.
1) You have to link to libpthread to get rid of the linker error:
gcc ..... -lpthread
(note that the -lpthread option must be the last one)!
2) exit(NULL); is wrong; NULL is for pointer types whereas exit wants an int to be supplied; use simply
exit(0);
instead.
The other warnings are just system-dependent pointer and integer size warnings; they can safely be ignored in most cases.
Pl. do not use the exit statement in your main function in this case, since the main may get exited and your threads also will terminate and you may not get the outputs of the print statement in the thread function.
Pl. use pthread_exit instead of exit in main so that even your main thread terminates the other threads can continue.

Resources