tags:

views:

199

answers:

6

hey :)

i have a problem. i wrote this code, a.h. a.c and the main.c:

file: a.h

#ifndef _a_H
#define _a_H
int poly (int a, int b, int c, int x);

int square (int x)
{
       return x*x;
}
#endif // _a_H

file: a.c

#include "a.h"
int poly (int a, int b, int c, int x)
{
     return a*square(x) + b * x +c;
}

file: main.c

#include <stdio.h>
#include "a.h"
int main()
{
    int p1 = poly1 (1 ,2 , 1, 5);
    int p2 = poly2 (1 ,1 , 3, 5);

    printf ("p1 = %d, p2 = %d\n", p1, p2);
    return 0;
}

and i got an error:

/tmp/ccKKrQ7u.o: In function 'square':
main.c:(.text+0x0): multiple definition of 'square'
/tmp/ccwJoxlY.o:a.c:(.text+0x0): first defined here
collect2: ld returned 1 exit status

so i moved the implementation of the function square to the a.c file and it works.

does any one know why?

thanx

+6  A: 

Don't put code in your header files. Both of your .c files include a.h, so both of them get an implementation of square, so your linker complains.

Carl Norum
A: 

You've answered your own question: you've defined square twice, once in each compiled file that includes a.h.

To avoid this you can make square a static function

static int square (int x)
{
   return x*x;
}

and add whichever inline hint your compiler uses, e.g. inline or __inline too.

Rup
+1  A: 

You can't write an implementation (function body) in a header file, otherwise the linker will find more than one reference to that function.

As a rule, put only declarations in header files, not definitions.

vulkanino
+3  A: 

When square() was in the header, it was included in both a.c and main.c, so each of the corresponding object files had its own square(), but without the static modifier, they had the exact same name. Moving it to a.c means that it's only defined once.

If you really want the function in the header file, you can define it with static inline thus:

static inline int square (int x)
{
       return x*x;
}

Static will mean that each .c file that includes the .h will have its own version of square(), inline means that the code will be dropped inline, and no function call will actually happen, which is probably what you want here

metadaddy
thanx:) but one thing that i dont understand, if in the header file i worte #ifndef _a_H#define _a_H etc' it should know not to include it twice, so if it was defined in a.c and in main.c so it should include it only once. no? am i wrong?
bass
The header guards prevent it being included twice in the same file (or 'compilation unit'). You're compiling two separate C files so each one will include the header and each one will get square compiled into the resulting object.
Rup
As an aside, GCC (and probably other compilers) do not always inline functions marked with `inline`, and sometimes inline static functions not explicitly marked for inlining. However, `inline` prevents compiler warnings when the static function is defined but not used. Hence, `static inline` is the way to go when defining tiny functions directly in a header file.
Joey Adams
@Matt: main.c and a.c are compiled in two separate, independent runs of the compiler (to produce main.o and a.o). Your include guards guarantee that the header is only included once in each run, but each compilation still includes the header once.
Nefrubyr
@Matt - the symbol _a_H is defined only to the C preprocessor, not the C compiler (they may be the same executable, but logically they are distinct). When you compile multiple files the preprocessor starts each source file with no symbols defined so it doesn't matter if main.c defined _a_H. When the preprocessor gets to a.c, it will no longer have any preprocessor symbols defined in main.c.
Ferruccio
+8  A: 

Generally speaking, *.c files are compiled into *.o files, and *.o files are linked to build the executable. *.h files aren't compiled, they are included textually in the *.c files, at the point they are #included.

So by #including "a.h" twice, in two separate *.c files, you've placed your definition for square() into two separate files. When these are compiled, you end up with two copies of square(), one in each *.o file. Then when you link them, the linker sees the two files, and generates an error.

How to avoid this? You've already discovered this. Don't put function definitions in *.h files. Put them in *.c files, and only put the function declarations in the *.h files.

Jeff Dege
Also, the `#define _a_H` happens once for each object file, so the `#ifndef _a_H` check succeeds twice.
Douglas
Usually it's recommended to inline such small functions. By declaring it in .c file they'll still have to have a standard non-inlined version exported by the symbol name from .o file. In these cases it's better to define them as `static inline int square (int x)` to avoid it. And if it happens, it's better to do it in header and not in several .c files.
ruslik
+4  A: 

This happens because your C compiler builds each .c file into an object (.o) file, and then links the object files to make the executable. The contents of a .c file and all the files it includes are known as a compilation unit.

Your example has two compilation units:

  • main.c, including stdio.h and a.h → compiles to main.o
  • a.c, including a.h → compiles to a.o

The linker (ld) then attempts to link the .o files but finds they both define square(), because it was in the shared a.h — hence the error. This is why, as some have already pointed out, you should not put function definitions in headers.

If you have the nm utility installed (which you should have), you can run

$ nm main.o
$ nm a.o

in the shell to see that square exists in both files.

(Edit: The term I was thinking of was actually translation unit, but on searching around they seem to mean pretty much the same thing.)

Nefrubyr
I don't want to clutter my answer with too much extra information, but it's worth adding that the steps of building a C program are generally (1) preprocess; (2) compile; (3) for some systems, assemble; (4) link. The whole process is confusingly often referred to as "compiling", but where the answers here say "compile" they specifically mean step (2).
Nefrubyr
+1 for the extra details, and for mentioning nm, I'd never heard of it, that's pretty cool.
Aaron H.