Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a function from another C file placed in another directory?

Tags:

Say I have a parent directory A with two subdirectories B and C.

Sub-directory C has a helper.c and helper.h as shown:

//helper.c

 void print(){
     printf("Hello, World!\n");
 }


//helper.h

void print();

Now, in sub directory B, I have a main.c which just calls the print function:

//main.c

#include<stdio.h>
#include"../C/helper.h"

void main(){
    print(); 

}

I tried the following commands for compiling main.c:

Command 1: gcc main.c  //Gives undefined reference to 'print' error
Command 2: gcc main.c ../C/helper.c   //Compiles successfully

Now I removed the #include"../C/helper.h" from main .c and tried the Command 2 again. It still works.

So I have the following questions:

i) What difference does it make whether the helper.h file is included or helper.c?

ii) Why command 1 fails?

iii) Is there a way to compile my C program without having to specify helper.c everytime?

like image 648
Aditya Naidu Avatar asked Jul 04 '16 10:07

Aditya Naidu


2 Answers

What happens when you execute:

Command 1: gcc main.c  //Gives undefined reference to 'print' error

When execute gcc main.c Compiler compiles main.c and creates objective file. This file will contain unresolved link to function print(). Because there is no implementation of function print() in main.c file. After compilation gcc tries to make full executable file. To do this gcc combines all objective files and tries to resolve all unresolved links. As you remember there is unresolved link for function print(), gcc can't find implementation and raise the error.

When you execute

Command 2: gcc main.c ../C/helper.c   //Compiles successfully

gcc compiles both files. Second file ../C/helper.c contains implementation of function print(), so linker can find it and resolve reference to it in function main().

i) What difference does it make whether the helper.h file is included or helper.c?

In your case helper.h contains forward declaration of function print(). This gives information to compiler how to make call of function print().

ii) Why command 1 fails?

See above.

iii) Is there a way to compile my C program without having to specify helper.c everytime?

Use make utility. Compile helper.c in separate objective file helper.o and use it in linkage command.

helper.o: ../C/helper.c ../C/helper.h
        gcc -c ../C/helper.c

main.o: main.c main.h
        gcc -c main.c

testprog: main.o helper.o
        g++ main.o helper.o -o testprog

See make utility manual for details. Commands should be indented by TAB.

like image 125
Beka Avatar answered Sep 28 '22 03:09

Beka


First you need to understand that #include simply adds whatever text is in the #include parameter to the position in the file the statement is in, for example:

//file1.h
void foo();

//main.c
#include "file1.txt"
int main(int argc, char **argv)
{
   foo();
   return 0;
}

Will cause the pre-compilation to generate this unified file for compilation:

//main.c.tmp
void foo();

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

So to answer your first and second questions:
When you include a header file (or any file) that only contains declarations (i.e function signatures) without definitions (i.e function implementations), as in the example above, the linker will fail in finding the definitions and you will get the 'undefined reference' error.

When you include a c code file (or any file) that contains definitions, these definitions will be merged to your code and the linker will have them, that's why it works.

and as for your third question It is bad practice to include c files directly in other c files, the common approach is to keep separate c files with headers exposing the functionality they provide, include the header files and link against the compiled c files, for example in your case:

gcc main.c helper.c -o out

Will allow you to include helper.c in main.c and still work because you instructed the compiler to compile both files instead of just main.c so when linking occurs the definitions from the compilation will be found and you will not get the undefined behavior error

This is, in a nutshell. I abstracted a lot of what's going on to pass on the general idea. this is a nice article describing the compilation process in fair detail and this is a nice overview of the entire process.

like image 32
Ishay Peled Avatar answered Sep 28 '22 04:09

Ishay Peled