C: redefinition of function when using #include

99 views Asked by At

I have encountered an issue in C that I am unable to recover, being "redefinition of [function]", and when I checked for a redefinition, I don't see any.

this always occur when the files are written like so:

file2.c

static int sampleFunction(){
    return 0;
}

file1.c

#include "file2.c"
static int anotherSampleFunction(){
    return sampleFunction()*2;
}

main.c

#include "file1.c"
#include "file2.c"
int main(){
    return sampleFunction()+anotherSampleFunction();
}

upon compiling, a

"redefinition of sampleFunction"

will occur in file2.c, even though the function wasn't redefined.
please note that the code is sample code: in reality, the source code is much more complicated, so I tried to simplify.
is there a way to fix this issue? thanks.

3

There are 3 answers

0
tnantaki On

because include will replace the code of file name that you specify.

So in file1.c will be

static int sampleFunction(){
    return 0;
}
static int anotherSampleFunction(){
    return sampleFunction()*2;
}

when come to main.c it's will defined sampleFunction() twice as you include.

So, in main.c you have to include only file1.c.

but in practical, You should use header files instead of include .c files.

0
Andrew On

Generally, it is not recommended to #include C source files into other C source files... you can end up (as you have) multiply including the same source file, and hence have multiple definitions and declarations!

However, the C pre-processor conveniently provides an alternative mechanism, the header file.

It is widely considered good practice that each C source file has an associated header file, which defines the external interface, so you should have something like:

file2.c

#include "file2.h"    // Include the externals

int sampleFunction()  // Must be global scope
{
    return 0;
}

file2.h

#ifndef HEADER_FILE2_H        // Protect against multiple inclusions
#define HEADER_FILE2_H
extern int sampleFunction();   // The external interface of file2.c
#endif

file1.c

#include "file1.h"            // Include the externals
#include "file2.h"            // Get file2.c's external interface

int anotherSampleFunction()   // Must be global scope
{
    return sampleFunction()*2;
}

file1.h

#ifndef HEADER_FILE1_H              // Protect against multiple inclusions
#define HEADER_FILE1_H
extern int anotherSampleFunction(); // External interface
#endif

main.c

#include "file1.h"   // Include the header files,
#include "file2.h"   /// ... not the source files

int main()
{
    return sampleFunction()+anotherSampleFunction();
}

Of course, you may have project wide common stuff too, so that would go in a further header file.

Increasing the number of seperate source files will make the build process slower... and be mindful of the coupling and cohesion of each module. Ideally, there should be few external references into, and out of, a given module.

0
JeremyP On

The way C handles #include statements is very simplistic. When it comes across #include file1.c all it does is replace that line with the entire contents of file1.c and then carry on. So, when compiling main.c, the first thing it does is replace the first line with the content of file1.c giving you:

#include "file2.c"
static int anotherSampleFunction(){
    return sampleFunction()*2;
}
#include "file2.c"
int main(){
    return sampleFunction()+anotherSampleFunction();
}

So it now wants to compile this, but the first line is now #include file2.c so the compiler replaces the first line again with the content of file2.c giving you this:

static int sampleFunction(){
    return 0;
}
static int anotherSampleFunction(){
    return sampleFunction()*2;
}
#include "file2.c"
int main(){
    return sampleFunction()+anotherSampleFunction();
}

Then it will continue compiling until it gets to the second #include and again replace it with the content of file2.c

static int sampleFunction(){
    return 0;
}
static int anotherSampleFunction(){
    return sampleFunction()*2;
}
static int sampleFunction(){
    return 0;
}
int main(){
    return sampleFunction()+anotherSampleFunction();
}

Now, as you can see, there are two definitions for sampleFunc in the same C file. This is an error.

The traditional way to get around this is to ut guard definitions into the files that will be included. These take the form

#ifndef SOME_UNIQUE_NAME_USUALLY_BASED_ON_THE_FILE_NAME
#define SOME_UNIQUE_NAME_USUALLY_BASED_ON_THE_FILE_NAME

// Content of the file

#endif

The first time the compiler comes across this, the name is undefined, so everything inside the #ifndef is included, including defining the name. The next time the compiler comes across this, the name is defined, so the entire #ifndef is omitted. For example, in file2.c you might do the following

#ifndef _FILE2_C
#define _FILE2_C

static int sampleFunction(){
    return 0;
}

#endif

Another thing you should bear in mind is that C files that are intended to be used in #include statements are usually called "header files" and, by convention, have a .h extension, not a .c extension. This is just a convention and the compiler attaches no relevance to it, but it is near universal, so you should stick to it.

Finally, you should consider not putting the function body in the header file. Doing it this way results in the function being compiled multiple times, once for each time the file is included. The normal way is to defined a header file and a C file with the header file just containing a declaration and the C file containing the definition. So you might have:

file2.h:

#ifndef _FILE2_H
#define _FILE2_H

int sampleFunction();

#endif

file2.c:

#include "file2.h"
int sampleFunction(){
    return 0;
}

Note I dropped the static keyword. This is because now sampleFunction() must be visible outside the compilation unit it is defined in. Also, technically, I should have used extern in file2.h but extern is implied for function declarations, so you don't need it.

Also, to compile this, you now need to compile two C files

cc file2.c main.c