[Home]TutorialFunctionDeclarationsAndDefinitions

TheSourcery | RecentChanges | Preferences | Index | RSS

In C/C++ there are declarations and definitions for functions. A declaration (often referred to as a prototype) informs the compiler how a function looks, or its signature. A definition contains how it works or laid out in memory.

int foo(int i, char* c);  /* a function declaration */

/* a function definition */
int foo(int i, char* c) {
  if (c && strlen(c) <  i)
    return c[i];
  else
    return '\0';
}

The compiler isn't very bright. It parses your source code in sequence bringing in #include files in place and expanding macros (actually the pre-compiler does this). Anyway upon encountering a function without a declaration it makes a guess what it should look like, thus the warning message (in C++ it is an error).

For example if you have the source file, myprog.c

int main(int argc, char** argv) {
  foo(5, "foobar");
  return 0;
}

When the compiler reaches the line with the call to foo(), it spits out the warning message you've seen because it has no clue what function foo() looks like. It can't tell you whether the parameters are correct for function foo() or not.

Try it...

$ gcc -Wall -c myprog.c
myprog.c: In function `main':
myprog.c:2: warning: implicit declaration of function `foo'

Therefore you need to tell it the declaration of foo().

Often foo() is called by different source modules so we place it in a header file both to save some typing and to prevent errors. So the above example myprog.c is changed to look like this.

#include "foo.h"

int main(int argc, char** argv) {
  foo(5, "foobar");
  return 0;
}

Inside foo.h we have:

int foo(int i, char* c);  

myprog.c now compiles cleanly without a warning message as your foo() function declaration gives it enough information about how the function looks.

Try it...

$ gcc -Wall -c myprog.c

However when we go to link this program to make an executable we'll get a error out of linkage editor (ld on linux), because we have not actually defined foo() anywhere at all.

Try it...

$ gcc -o myprog myprog.o
myprog.o(.text+0x35):myprog.c: undefined reference to `_foo'
collect2: ld returned 1 exit status

The C compiler prefixes all your function names with leading underscores when it creates object files (myprog.o). This is known as name mangling.

So we'll create another source module, and call it myfoo.c.

It looks like this:

int foo(int i, char* c) {
  if (c && strlen(c) <  i)
    return c[i];
  else
    return '\0';
}

Let's compile it.

$ gcc -Wall -c myfoo.c
myfoo.c: In function `foo':
myfoo.c:2: warning: implicit declaration of function `strlen'

Whoops! This is unfortunate. Apparently the compiler doesn't even know what the functions in it's own runtime library look like, in particular strlen(). I did tell you it wasn't very smart. Now the worst thing we could do would be to guess and write our own function declaration for strlen(). Instead we'll do the right thing and include the proper header file. But what header file to include?

$ man strlen

STRLEN(3)                           LIBC                           STRLEN(3)

NAME
       `strlen'--character string length

SYNOPSIS
            #include <string.h>
            size_t strlen(const char *STR);
...

There it be in black and white, along with more than we needed to know right now. Aren't man pages handy? So let's change myfoo.c:

#include <string.h>

int foo(int i, char* c) {
  if (c && strlen(c) <  i)
    return c[i];
  else
    return '\0';
}

Note the use of angle brackets for system header files instead of quotes for our header files. Why? Most compilers search for the headers using a different order depending on which format you use.

Let's compile it...

$ gcc -Wall -c myfoo.c

Not a peep. Now let's link both modules myprog.o and myfoo.o into an executable myprog:

$ gcc -o myprog myprog.o myfoo.o

Again not a peep. We can run it.

$ ./myprog

Not a peep. But then it doesn't print anything either.

Now backing up a bit. Suppose foo() and main() are in the same file myprog.c, like this:

#include <string.h>

int foo(int i, char* c) {
  if (c && strlen(c) <  i)
    return c[i];
  else
    return '\0';
}

int main(int argc, char** argv) {
  foo(5, "foobar");
  return 0;
}

Let's compile it...

$ gcc -Wall -c myprog.c

No warnings and there's no function declaration for foo! What happens is that when the compiler sees the function definition for foo(), and there's been no function declaration for it yet, the function definition doubles as both the declaration and definition.

Simple eh?

This is okay if we're only going to call foo() from the module myprog.c, though we'll still have to write a declaration if we ever want to call it from some other module. (Also if we know for certain only the module myprog.c will ever call it, we should declare it as static: i.e. static int foo(int, char*); )

Let's mess with the compiler's mind, by screwing up our call to foo().

#include <string.h>

int foo(int i, char* c) {
  if (c && strlen(c) <  i)
    return c[i];
  else
    return '\0';
}

int main(int argc, char** argv) {
  foo("foobar", 5);  /* flipped the parameters around */
  return 0;
}

$ gcc -Wall -c myprog.c
myprog.c: In function `main':
myprog.c:11: warning: passing arg 1 of `foo' makes integer from pointer without a cast
myprog.c:11: warning: passing arg 2 of `foo' makes pointer from integer without a cast

Ah... just a warning about some nonsense. I can't make heads nor tails out of it.

We can just ignore it right? :-P

$ gcc -o myprog myprog.o

It links cleanly...

$ ./myprog
Segmentation fault (core dumped)

Explodes on execution. Looks like the warnings about the parameters of foo() were somewhat important, and not the babbling of some mad compiler.

So let's put the call to foo() back the way it was, except we'll mess with the compiler by changing the order in which the functions are defined.

#include <string.h>

int main(int argc, char** argv) {
  foo(5, "foobar");  
  return 0;
}

int foo(int i, char* c) {
  if (c && strlen(c) <  i)
    return c[i];
  else
    return '\0';
}

$ gcc -Wall -c myprog.c
myprog.c: In function `main':
myprog.c:4: warning: implicit declaration of function `foo'

There we go back to same warning message. But we really like our code in this order with main at the top, so we'll add the foo() function declaration at the top of the file.

#include <string.h>

int foo(int i, char* c);  /* here be the declaration */

int main(int argc, char** argv) {
  foo(5, "foobar");      /* here be the first time the compiler needs it */
  return 0;
}

int foo(int i, char* c) {  /* here be the definition */
  if (c && strlen(c) <  i)
    return c[i];
  else
    return '\0';
}

$ gcc -Wall -c myprog.c

$ gcc -o myprog myprog.o

No warnings, and it links okay.

The End


TheSourcery | RecentChanges | Preferences | Index | RSS
Edit text of this page | View other revisions
Last edited February 1, 2010 7:17 pm by Tyche (diff)
Search:
All material on this Wiki is the property of the contributing authors.
©2004-2006 by the contributing authors.
Ideas, requests, problems regarding this site? Send feedback.