Re: unusual behaviour of program under linux....

From: Floyd Davidson (floyd_at_barrow.com)
Date: 06/18/03


Date: 18 Jun 2003 09:29:52 -0800

seemanta_18@yahoo.com (seemanta dutta) wrote:
>greetings linux gurus...
>
>i have a mysterious error coming up in my seemingly simple code..plase
>help me.
>following is my code:
>( i am using gcc on redhat linux 7.2)
>
>...

Your immediate problem is failing to initialize the two
pointers, as Frank Cusack has pointed out.

There are a couple of other problems here, and some very good questions
you had, which shouldn't go without comment.

>#include<stdlib.h>
>#include<unistd.h>

You have not included stdio.h, and thus your use of printf() is
without a prototype or declaration. This suggests that you are
not using the facilities of your compiler to spot problems.

First, you want to use a simple Makefile so that the compiler can
have a very complex command line without you having to type it in
every time. You want to be able to compile using "make", and there
are several command line options you want to use when invoking gcc.

Here is what I happen to use,

  gcc -O -g -ansi -W -Wall -Wcast-align -Wcast-qual -Wshadow \
      -Wnested-externs -Wstrict-prototypes -Waggregate-return \
      -Wmissing-prototypes -Wtraditional -Wpointer-arith -c foo.c

There are times when some of these have to be removed though.
The -ansi option can conflict with prototypes in unistd.h, for
example. Likewise "-Wpointer-arith" can produce warnings from
some system headers.

You do want to read the man page for gcc and see what each of
those options does. In particular you should almost never have
a reason to invoke gcc to compile C source code without using
the -W and -Wall options.

Here are the warning messages produced when I compiled your short
program with the above options. Note that it pointed out the
specific problems which you have asked about, plus a few others.

  foo.c:4: warning: function declaration isn't a prototype
  foo.c:5: warning: function declaration isn't a prototype
  foo.c:15: warning: function declaration isn't a prototype
  foo.c: In function `main':
  foo.c:19: warning: control reaches end of non-void function
  foo.c: At top level:
  foo.c:21: warning: function declaration isn't a prototype
  foo.c: In function `foo':
  foo.c:23: warning: `localVar' might be used uninitialized in this function
  foo.c: At top level:
  foo.c:30: warning: function declaration isn't a prototype
  foo.c: In function `bar':
  foo.c:34: warning: implicit declaration of function `printf'
  foo.c:34: warning: format argument is not a pointer (arg 3)
  foo.c:32: warning: `newLocalVar' might be used uninitialized in this function

In addition to uninitialized variables, you are not using prototypes:

>void foo();
>void bar();

These should have been

  void foo(void);
  void bar(void);

Also the main() function is declared to return a type int, but you don't
have a return statement to supply an int value.

Essentially, if you compile with those options enabled, and then code to
eliminate any warnings produced, you will 1) spot many problems, and 2)
learn a great deal.

For example, it might appear that you don't really benefit from including
stdio.h just to provide a prototype for printf() because it appears to
work without it. Wrong! If you have the prototype in scope, compiling
again produces more warnings,

  foo.c: In function `bar':
  foo.c:49: warning: format argument is not a pointer (arg 4)
  foo.c:45: warning: `newLocalVar' might be used uninitialized in this function

Here is the code (note the several changes, including a consistant
formatting style):

  void
  bar(void)
  {
    struct foo * foobaz;
    int newLocalVar;

    foobaz = malloc(sizeof *foobaz);

    printf("addr of globalVar=%p addr of newLocalVar=%p\n",
           globalVar,
           newLocalVar);
  }

With stdio.h included the compiler can warn about using the
value of newLocalVar instead of the address of the variable,
which is what you wanted, in the printf() call.

In this case the warning about an uninitialized variable will
go away once the above is corrected simply because while it
is never initialized, it is also never used.

  void
  bar(void)
  {
    struct foo *foobaz;
    int newLocalVar;

    foobaz = malloc(sizeof *foobaz);

    printf("addr of globalVar=%p addr of newLocalVar=%p\n",
           globalVar,
           &newLocalVar);
  }

Note that I changed the way malloc() is called too. There isn't
really much difference, but it demonstrates a slightly more
versatile method. If you change foobaz to a different type of
struct, or even just change the name, using "sizeof(struct foo)"
means it has to be changed too. Using "sizeof (*foobaz)" means
whatever type foobaz is, the proper size will be returned.

In addition, I've not used parens around "*foobaz", and instead
it is "sizeof *foobaz". Again, a minor point that doesn't
change anything. But it does demonstrate that "sizeof" is an
operator, not a function.

...

>then i wrote another program to get the exit status...of which i am
>not sure
>the way to convert the exit code into meaningful strings...

I don't understand how you even managed to compile this. Here is
what happened when I tried,

  foo.c:8: warning: function declaration isn't a prototype
  foo.c: In function `main':
  foo.c:10: `pid_t' undeclared (first use in this function)
  foo.c:10: (Each undeclared identifier is reported only once
  foo.c:10: for each function it appears in.)
  foo.c:10: parse error before "pid"
  foo.c:12: `pid' undeclared (first use in this function)
  foo.c:18: warning: implicit declaration of function `printf'
  foo.c:22: warning: implicit declaration of function `perror'
  foo.c:24: warning: control reaches end of non-void function
  make: *** [foo.o] Error 1

You don't have stdio.h included for perror() and printf(), and
you don't have sys/ctypes.h included to define pid_t. By adding
those, and a return statement to the main() function, this code
compiles without errors or warnings.

>#include<unistd.h>
>#include<stdlib.h>
>#include<sys/wait.h>
>#include<errno.h>

I'm not sure what method you are using to decide which headers to
include. You need to read the man page for each and every function
used, and include the headers that the man pages say are necessary.

You've used the fork() function, hence:

  #include <sys/types.h>
  #include <unistd.h>

You've used the waitpid() function, hence:

  #include <sys/types.h>
  #include <sys/wait.h>

You've used the execl() function, hence:

  #include <unistd.h>

You've used the perror() function, hence:

  #include <stdio.h>

(Note that errno.h is not needed for just using perror().)

So the list of header includes should be,

  #include <sys/types.h>
  #include <unistd.h>
  #include <sys/wait.h>
  #include <stdio.h>

>int main()
>{
> int status;
> pid_t pid;
> if((pid=fork())==0)
> {
> execl("./test","./test",NULL);
> //test is the name of the first program shown above...
> }
>
> else

Yikes. This else statement also executes if fork() fails and returns
a -1. That would be a bummer. I prefer to use a switch/case statement,
but you could just throw in "if (pid == -1) ...". Here's an example of
using switch/case,

        #include <stdio.h>
        #include <sys/types.h>
        #include <unistd.h>
        #include <errno.h>

        pid_t pid;

        switch (pid = fork()) {
        case -1:
          perror("fork");
          exit(EXIT_FAILURE);
        case 0;
          /* code for child process */
        default:
          /* code for parent process */
        }
          

> {
> waitpid(pid,&status,0);
> if(WIFEXITED(status))
> printf("%d \n",WEXITSTATUS(status));

That is fine down to here.

> errno=WEXITSTATUS(status); // is this correct??
> perror("test");

The value of errno is set by various system calls. You don't
want to use it as if it were a program variable. It indicates
the status of function calls, not the return status of programs.

The return status of your program is set by the value you choose
when you call exit() or when you place a return statement in
main(). Your program didn't have either, and hence was
returning whatever odd number happened to be in the right cpu
register at the wrong time.

If you put "return 2;" into your program's main(), the above
will print out that the return status is 2. If you put "return
0;", it will show 0 as the status. Hence perror() is not
related at all, and except for 0 will give you a text message
that is totally unrelated to your program.

>the output of the above program is this:
>
>addr of globalVar=0x400168e4 addr of newLocalVar=0x400168e4
>01000:
>01000: calling fini: /lib/i686/libc.so.6
>01000:
>62
>test: Timer expired
>
>i am unable to make out any of this..please help me...

Now you can see why it didn't make much sense!

>also tell me if there is any difference in the exit codes of system
>calls like
>open,creat..that set errno variable and the exit codes of processes
>that are collected via the wait system call...

If you have more questions about that, do ask. It isn't something
that becomes crystal clear overnight!

>thanks in advance...
>urs sincerely...
>seemanta ;)

-- 
Floyd L. Davidson           <http://web.newsguy.com/floyd_davidson>
Ukpeagvik (Barrow, Alaska)                         floyd@barrow.com


Relevant Pages

  • compiling ibcs on Debian 3.0 / 2.4.19 kernel and on Debian 2.2r5 / 2.2.26 kernel
    ... warning: this is the location of the previous ... declaration isn't a prototype ... incompatible pointer type ...
    (Debian-User)
  • Re: Urgent C Questions
    ... int, not void. ... Then you need to turn up the warning level on QuickC. ... 3  missing prototype for 'main' ... stdio.h contains the declaration for printf: ...
    (comp.lang.c)
  • Re: Warnings in lcc-win
    ... the default and the user has asked for a higher warning level. ... function earlier in the source, without having a prototype, is ... I am NOT talking about K&R style declaration versus ... Are you saying that as long as this appears before any call to func() ...
    (comp.lang.c)
  • Re: Warnings in lcc-win
    ... the default and the user has asked for a higher warning level. ... But I do not like the wording for the second one. ... function earlier in the source, without having a prototype, is ... I am NOT talking about K&R style declaration versus ...
    (comp.lang.c)
  • Re: Dynamic arrays
    ... >compile. ... 4: conflicting types for `da' ... 4: warning: implicit declaration of function `malloc' ... 4: warning: initialization makes integer from pointer without a cast ...
    (comp.lang.c)