LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 09-18-2010, 12:53 PM   #1
pr_deltoid
Member
 
Registered: Jun 2010
Distribution: Fedora
Posts: 289

Rep: Reputation: 41
Unhappy Confusion about C header files and object files.


I'm a little confused about this, and I can't find a good explanation of it anywhere.
When is it good to use separate translation units and object files and link them into the main C program, and when is it good to include the header files in the main C program? I don't understand if most people include header files or if most people just link in object files and use their contents in the main program. It's sort of a simple question, but it's confusing to me and that's why I need help with it. I sort of don't understand the difference, or if there's really no difference other than the way the final result is achieved, which way is better or preferred, etc...

For example:
Code:
main.c:
    #include "part_of_my_program.h"

    /* things from part_of_my_program.c */
or:
Code:
main.c:
    /* things from part_of_my_program.c */

cc -o my_program main.o part_of_my_program.o
Can anyone help me with a simple explanation of the difference, or which one is preferred or better, or something to help my confusion?

I've read a little on the ELF format... so is there no difference in the end result? It's just a matter of preference or necessity, and where the information is to begin with?

Last edited by pr_deltoid; 09-18-2010 at 01:23 PM.
 
Click here to see the post LQ members have rated as the most helpful post in this thread.
Old 09-18-2010, 01:02 PM   #2
pr_deltoid
Member
 
Registered: Jun 2010
Distribution: Fedora
Posts: 289

Original Poster
Rep: Reputation: 41
It seems to me like the end result would be the same, and it would just be a matter of preference or necessity, or maybe specific situations where it would be a better idea to just link in an object file. Everything ends up the same in the final ELF file, so it's probably more common to include the header files, huh?
Or is it common to just make a bunch of separate object files and link them together with the main object file, that includes the main() function?
Any kind of help clearing this up would be appreciated.

Last edited by pr_deltoid; 09-18-2010 at 01:16 PM.
 
Old 09-18-2010, 01:16 PM   #3
pr_deltoid
Member
 
Registered: Jun 2010
Distribution: Fedora
Posts: 289

Original Poster
Rep: Reputation: 41
The general mixing of header files and object files and linking is confusing to me.
What's necessary? Do people mix the inclusion of header files and the linking of object files? Can anyone point me to a good tutorial on this?
I thought I understood this process, and I just realized that I have no idea what's happening and why things are done the way they are, when I think of the overall header files, object files, and linking being mixed together like they are.
If you can do without the inclusion of a header file, if you just link in the object file of the .c file that you're including things from, what difference does the inclusion of the header file make?


Last edited by pr_deltoid; 09-18-2010 at 01:22 PM.
 
Old 09-18-2010, 01:40 PM   #4
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
First you need to understand the difference between declaring and defining in C.

Good programming of large projects in C usually involves declaring functions in .h files and defining them in .c files.

You can call functions in C without first declaring them, but it is not a good practice. So any .c file that includes calls to a function should #include the .h file that declares the function.
 
Old 09-18-2010, 01:58 PM   #5
pr_deltoid
Member
 
Registered: Jun 2010
Distribution: Fedora
Posts: 289

Original Poster
Rep: Reputation: 41
Do you know a simple explanation of whether there is any difference in the final ELF executable depending on whether you include the header file of the .c file that ends up being a linked-in .o object file or you just link in the .o object file?
 
Old 09-18-2010, 02:18 PM   #6
pr_deltoid
Member
 
Registered: Jun 2010
Distribution: Fedora
Posts: 289

Original Poster
Rep: Reputation: 41
Alright.

Here's a short program:

testhello.h:
Code:
#include <stdio.h>

void testhello();
testhello.c:
Code:
#include "testhello.h"

void testhello()
{
	printf("hello\n");
}
main.c:
Code:
#include "testhello.h"

int main()
{
	testhello();
	return 0;
}
Regardless of whether #include "testhello.h" is in main.c, it will compile fine.

With #include "testhello.h":
Code:
[prdeltoid@home /usr/home/prdeltoid/C]$ gcc -Wall -o test main.c testhello.c
[prdeltoid@home /usr/home/prdeltoid/C]$ ./test 
hello
Without #include "testhello.h":
Code:
[prdeltoid@home /usr/home/prdeltoid/C]$ gcc -Wall -o test main.c testhello.c
main.c: In function 'main':
main.c:3: warning: implicit declaration of function 'testhello'
[prdeltoid@home /usr/home/prdeltoid/C]$ ./test 
hello
What's the difference? Is the ELF file any different? Why bother with the inclusion of testhello.h in main.c if nothing changes except the implicit declaration warning? Do people usually include testhello.h just to add clarity and to avoid the warning?

Last edited by pr_deltoid; 09-18-2010 at 02:19 PM.
 
Old 09-18-2010, 02:19 PM   #7
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
Quote:
Originally Posted by prdeltoid View Post
Do you know a simple explanation of whether there is any difference in the final ELF executable depending on whether you include the header file of the .c file that ends up being a linked-in .o object file or you just link in the .o object file?
If you are talking about ordinary headers (declaring functions, etc.) and about ordinary .o files (defining those functions) then the question you are asking is almost the same as asking the pitfalls of calling undeclared functions in C.

If you call an undeclared function in C, the compiler will make assumptions about the parameter types and return type of the function. Those assumptions may not be correct, in which case the compiled function would not be correct, in which case the difference in the final ELF executable is correct vs. incorrect.

A header might also declare struc's, enum's typedef's, etc. that other .c models need. Then failing to include the header will cause an error at compile time.

Last edited by johnsfine; 09-18-2010 at 02:21 PM.
 
1 members found this post helpful.
Old 09-18-2010, 02:35 PM   #8
pr_deltoid
Member
 
Registered: Jun 2010
Distribution: Fedora
Posts: 289

Original Poster
Rep: Reputation: 41
I didn't know that non-function declarations or definitions wouldn't work. I just tried what I posted before with an enum and a typedef and received compiler errors. Do you know a simple explanation for why an object file with nothing but includes and functions will work the way I posted above, but typedef, enum, etc. won't?


It's the ELF format and the way the linking works, right?

Thanks very much for your help, and now that I've thought about it for a while and learned that things other than functions don't work that way, I have a much better understanding.

Last edited by pr_deltoid; 09-18-2010 at 02:38 PM.
 
Old 09-18-2010, 02:51 PM   #9
tommylovell
Member
 
Registered: Nov 2005
Distribution: Raspbian, Debian, Ubuntu
Posts: 380

Rep: Reputation: 103Reputation: 103
I'm no expert, so everyone feel free to correct me where I'm wrong.

You can include a lot of things in an include file, but I think your question really is about the C function prototypes. The function prototypes merely tell the compiler what, if anything, gets passed on the stack to a called function; and what, if anything, gets returned on the stack from a called function.

The prototypes produce no code. They are just there to make sure that a function is called properly.

As johnsfine said, prototypes are optional. With the pre-ANSI C compiler prototypes were optional. But the coder really needed to keep track of all of that stuff. If you coded a call to a function and passed two int variables on the stack, and the function expected three and popped three off the stack, a painful debugging session would follow... With ANSI C compilers there is a flag you have to specify so that strict prototyping is not done.

It doesn't matter if the function is coded in the main C program, or external to it and linked into the elf executable later (except maybe the order of the code segments). But functionally they have the same content.

The readelf and objdump commands can show you information about your executables. ('man elf' will give you the gory details of an elf binary.)
 
2 members found this post helpful.
Old 09-19-2010, 12:22 AM   #10
tommylovell
Member
 
Registered: Nov 2005
Distribution: Raspbian, Debian, Ubuntu
Posts: 380

Rep: Reputation: 103Reputation: 103
I know this is marked as SOLVED, but just to illustrate...

Your code, slightly modified:

Code:
[root@athlonz testhello]# cat testhello.h
#include <stdio.h>

int  testhello(int howmany, char * who);


[root@athlonz testhello]# cat testhello.c
#include "testhello.h"

int  testhello(int n, char * w)
{
        printf("%i. hello %s\n", n, w);
        return 1;
}


[root@athlonz testhello]# cat main.c

int main()
{
        testhello(1, "world");
        return 0;
}
Compiled and executed:
Code:
[root@athlonz testhello]# gcc -c -o testhello.o testhello.c 

[root@athlonz testhello]# gcc -c -o main.o main.c 

[root@athlonz testhello]# gcc -o test main.o testhello.o

[root@athlonz testhello]# ./test
1. hello world
It works ok.

Then we change the testhello call in main.c. The "1" is a string, not an int which is what testhello is expecting.

Code:
[root@athlonz testhello]# vi main.c 

[root@athlonz testhello]# cat main.c
int main()
{
        testhello("1", "world");
        return 0;
}

[root@athlonz testhello]# gcc -c -o main.o main.c 

[root@athlonz testhello]# gcc -o test main.o testhello.o

[root@athlonz testhello]# ./test
4195870. hello world
So, how easy is it to spot this error? And depending on other factors it can also seg fault.

Quote:
Do people usually include testhello.h just to add clarity and to avoid the warning?
yes, ...and to help to avoid debugging later on.
 
2 members found this post helpful.
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Including header files and source files for classes Feenix Programming 8 09-28-2005 10:53 AM
gcc header files and cpp files? EchO Linux - Software 3 03-01-2005 01:14 AM
c header files in linux in place of header files in windows? harun_acs Programming 1 03-17-2004 02:24 AM
simple question - can you move header and lib files from one box to ano dewcansam Linux - General 3 11-25-2001 12:35 AM
simple question - can you move header and lib files from one box to another without a dewcansam Linux - Newbie 3 11-06-2001 05:35 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 04:33 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration