APLawrence.com -  Resources for Unix and Linux Systems, Bloggers and the self-employed
RSS Feeds RSS Feeds











(OLDER) <- More Stuff -> (NEWER) (NEWEST)
Printer Friendly Version
->
-> Writing and Compiling C programs on Linux


Writing and Compiling C programs on Linux

Learn the basics of compiling C programs.




Most Linux and Unix programs are written in C. When you download source for a project, it will often be C or C++ source code. You don't necessarily need to know a darn thing about C or anything else to compile the source if you aren't changing it. It may be helpful for you to understand a bit if you are having problems with the compile, but even that isn't really necessary.

Just to cover that ground for the folks who stumbled across this and don't care about learning: the stuff you downloaded probably came with a README file (or files). Try "ls *READ* *read*" and if you see anything at all, take a look: "less *READ* *read*" would also be a start. If you see a file named "configure", do "./configure". If this is a Perl project, you may see a "Makefile.PL" - in that case try "perl Makefile.PL". Try "ls Make*" - if you only see one "Makefile", try "make". There really, really should be a "readme" if your required steps are much different than "./configure; make; make install"

Basic C programming

Typically, tutorials like this start you out with a "Hello, World" program, a very simple program that just prints 'Hello, World" or something like it on your screen. I'm going to do it a bit differently. I am going to start you off with mistakes, and show you what happens. Why? Because you are going to make some or all of these mistakes anyway, and they will frustrate and annoy you. I can't possibly imagine every mistake you might make, but I can remember most of the screwups I have made, so that's at least a good beginning? Ready for some code that won't work? Let's do it:

Hello World

Create this file with a text editor:


echo "Hello World";
 

You've learned the very first thing about C - lines always end with a ";". Well, that's not quite true, but this kind of line does.

Call it "hello.c" (because that's what these are always called).

Compiling

You have created a C "source" file - the human readable source for your program. It needs to be "compiled" - turned into machine language that your cpu can actually use. There are two basic ways you can do that: use "gcc" (or "cc", which is usually the same thing) or "make".

Ordinarily, "make" requires a "makefile" to tell it what to do, but for very simple files like this, "make" is smart enough to do it without help - just "make hello" is all it needs. Notice that your source file is "hello.c" but you would say "make hello" - no ".c".

Make would actually run gcc, and specifically it would do "gcc -o hello hello.c". You could also do "gcc hello.c", but (assuming it were successful), that would create an executable (a program ready to use) called "a.out" rather than "hello". That -o option to gcc tells it what you want your program to be called. You could say "gcc -o mybigbadprogram hello.c" if you wanted to.

What's with the "a.out"? There has always, since the early days of Unix, been a header file called a.out.h which described the format that an executable needed to be for the kernel to use it. I lied a little bit when I said compiling creates machine language - the kernel needs a bit more structure around that machine language in order to know how to recognize it as an executable at all, and then how to properly set it all up in memory somewhere. That's all deep voodoo stuff though, and we are a long way from worrying about that. But that's why gcc creates "a.out" if you don't tell it otherwise.

So now, simply type "make hello". You should see:

cc     hello.c   -o hello
hello.c:1: syntax error before string constant
make: *** [hello] Error 1
 

Hmmm. What's wrong? Well, lot's of things, but you don't know that yet. And what you really could use right now is something that used to come with Unix systems, but usually gets left out of Linux. That something is called "lint" and you can go get it from http://www.splint.org/manual/

I'll wait here while you go get that. For my RedHat box, I got the "lclint-2.5q-3.i386.rpm" and just did an "rpm -iv lclint*".

If you went searching for "linux lint" ('cuz you don't trust me, do you?), I bet you found a page or two that told you "gcc -Wall is roughly equivalent to lint". Yeah. And I'm roughly equivalent to Robert Redford, too. But just to give 'em a chance, let's try it while your lclint is downloading:

$  gcc -Wall hello.c
hello.c:1: syntax error before string constant
$
 

Much more helpful, wasn't it? OK, let's give lclint a crack at it:

lclint hello.c
LCLint 2.5q --- 26 July 2000

hello.c:1:19: Parse Error: Inconsistent function declaration: echo :
               int. (For help on parse errors, see lclint -help parseerrors.)
*** Cannot continue.
 

OK, so that's not all that helpful. Actually, "gcc -Wall" is pretty good at being helpful - it is a lot more like lint than I am like Robert Redford. Trust me, though, you'll be glad to have lint later, because sometimes it can give you a different view of the bonehead mistakes you will make. It's always nice to have a second opinion, isn't it?. And it did give us a little more information here that gcc did not.

Actually, we have some real problems. First, , we can't just start off writing code like this. This isn't bash or Perl, this is C. There are RULES, and there are a lot more than "end every line with a semi-colon". Let's change it a bit:

foo() 
{
echo "Hello World";
}
 

Now THAT looks a lot closer to a real C program. Or a bash function. It's still a useless pile of bytes to the compiler, though:

$  gcc hello.c
hello.c: In function `foo':
hello.c:3: `echo' undeclared (first use in this function)
hello.c:3: (Each undeclared identifier is reported only once
hello.c:3: for each function it appears in.)
hello.c:3: syntax error before string constant
$ lclint hello.c
LCLint 2.5q --- 26 July 2000

hello.c: (in function foo)
hello.c:3:1: Unrecognized identifier: echo
  Identifier used in code has not been declared. (-unrecog will suppress
  message)
hello.c:3:19: Parse Error. (For help on parse errors, see lclint -help
             parseerrors.)
*** Cannot continue.
 

Do you need to be hit over the head? Obviously the problem is that "echo". There's no "echo" in C! What idiot told you to use "echo"?

Oh. Yeah, that was me. OK, right, C has "printf". Shells use echo, Perl uses "print" and "printf", but C uses "printf". Got that? Let's try again, shall we?

$ cat hello.c
foo()
{
printf "Hello World";
}

$ gcc hello.c
hello.c: In function `foo':
hello.c:3: `printf' undeclared (first use in this function)
hello.c:3: (Each undeclared identifier is reported only once
hello.c:3: for each function it appears in.)
hello.c:3: syntax error before string constant
$
 

Aww, c'mon! I KNOW printf is right! Wait a minute, I can even show you in the man page: "man 3 printf". Look, right near the top it shows how to use it:

 int printf(const char *format, ...);
 

.. whatever that means.

Actually, it means this: printf returns an integer, and requires at least one string argument ("char *" means string to you, at least for now). We gave it a string argument, but oops, we did leave out those parentheses, didn't we? Let's fix that and try again:

$ cat hello.c
foo ()
{
printf("Hello World");
}
[tonylaw@kerio tonylaw]$ gcc hello.c
/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/../../../crt1.o(.text+0x18): In function `_start':
: undefined reference to `main'
collect2: ld returned 1 exit status
 

Oh, yeah, that helped a WHOLE bunch. What does "lclint" think?

$ lclint hello.c
LCLint 2.5q --- 26 July 2000

hello.c: (in function foo)
hello.c:4:2: Path with no return in function declared to return int
  There is a path through a function declared to return a value on which there
  is no return statement. This means the execution may fall through without
  returning a meaningful result to the caller. (-noret will suppress message)

Finished LCLint checking --- 1 code error found
 

Hmm.. what about that "undefined reference to `main'"? In all the C examples I've ever seen, they started with "main", not "foo".

True enough. By the way, did you notice that we stopped using "make hello" and did "gcc hello.c" instead or did I slip that by you? Either one is fine, at least for what we are trying now. It's not like anything is working, anyway. But let's try the "main" thingy.

$ cat hello.c
main ()
{
printf("Hello World");
}
$ make hello
cc     hello.c   -o hello
 

Holy Compilers, Robin, the darn thing worked! Try "./hello":

$ ./hello
Hello World$ 
 

Looks like it needs a line feed, but that's easy:

main ()
{
printf("Hello World\n");
}
 

That fixes that. Actually, though, it shouldn't have. We missed something in the man page, and it could have been really important. Let's add something to the file that will break it. Never mind why we are doing this, but add "FILE *a;" as shown here::

$ cat hello.c
main ()
{
FILE *a;
printf("%s\n","Hello World");
}

$ make hello
cc     hello.c   -o hello
hello.c: In function `main':
hello.c:3: `FILE' undeclared (first use in this function)
hello.c:3: (Each undeclared identifier is reported only once
hello.c:3: for each function it appears in.)
hello.c:3: `a' undeclared (first use in this function)
make: *** [hello] Error 1
 

The fix is quick and simple: one line at the top of the file. The man page for printf actually told us about this: "#include <stdio.h>":

#include <stdio.h>
main ()
{
FILE *a;
printf("%s\n","Hello World");
}
 

"make hello" works fine with that. Why? Because the file /usr/include/stdio.h defines FILE (among a lot of other things). Here's a good rule to follow: you will almost ALWAYS need stdio.h. Whenever the man page for a function you want mentions including some file, it's a pretty good bet that your program is not going to work without it. And there may even be more to do. Look at this:

#include <stdio.h>
#include <math.h>
main ()
{
printf("pi = %.5f\n", 4 * atan(1.0));
}
 

We looked up the atan function and found it needs math.h. We've told the compliler to include it. Trust me, the program is right. But..

$ gcc -o pi pi.c
/tmp/ccLmoMxc.o(.text+0x33): In function `main':
: undefined reference to `atan'
collect2: ld returned 1 exit status
 

What we need here is a special compiler flag:

gcc -o pi -lm pi.c
 

"lm" tells it to link in the math libraries. Math libraries? Sure, you didn't think C by itself knows how to do arc tangents, did you? C by by itself doesn't know much. Most of its functions - the things you can use - come from external libraries that get linked in. How would you know when you need to use a special library? It's just something you have to learn. Usually, if there is a special linker flag, the man page will have told you. In the case of atan, it does not, so you just need to remember that you need "-lm" when you see "#include <math.h>" mentioned.

Make files

With just this much knowledge, you can actually write C programs. You don't need make files (though make files are of course very useful for bigger programs). If the program needs no special compiler flags, "make" is smart enough to know what to do all by itself, as we saw earlier. As you write bigger programs, you'll find that "gcc -Wall" and "lclint" will help you spot your mistakes. But let's "make" something a bit more complicated. It's two files, and we'll be using a new compiler switch:

$ cat pi.c
#include <math.h>

mypi()
{
printf("pi = %.5f\n", 4 * atan(1.0));
}

$ cat hello.c
#include <stdio.h>
main ()
{
mypi();
}

$ gcc -c pi.c
$ gcc -c hello.c
$ gcc -lm -o hello hello.o pi.o
$ ./hello
pi = 3.14159
 

That's all good, and it works, but all those gcc's would get annoying real fast. This is where we use "make".

$ cat Makefile
pi.o:   pi.c
        gcc -c pi.c

hello.o:        hello.c
        gcc -c hello.c

hello:  hello.o pi.o 
        gcc -lm -o hello hello.o pi.o


You need TABS after each ":" and before the gcc's on the lines that follow each "rule". Basically, a makefile says "to make x, you need these files, and you run this command

target : TAB files needed
TAB command needed


Leave out tabs and make will complain:

Makefile:5: *** missing separator.  Stop
 

But we got the tabs right, so now we can do "make hello" and it works:

$ make hello
gcc -c hello.c
gcc -c pi.c
gcc -lm -o hello hello.o pi.o
$ ./hello
pi = 3.14159
$ 
 

You are going to make more mistakes. If you are like most of us, pointers and indirect pointers (char *this, char **that) are going to confuse you, and you'll misuse them. Lint and gcc -Wall will help you somewhat, but you'll still probably screw up. You'll forget that you are referencing something on a long overwritten stack. You'll blithely dereference past the end of an array and your programs will crash as they get killed off for trying to change somebody else's memory space. Don't feel badly, other people have stumbled and lurched down the same path before you. Buy a beginner's C book, and have at it.

Here's some references that can help:


The Top 10 Ways to get screwed by the "C" programming language
Common practices to help avoid errors in C programs (a bit more advanced; save this one for later)
warning: empty translation unit

This post by Lew Pitcher does a good job explaining GNU libc, glibc, Glib, glibc2, and libstdc++.




If this page was useful to you, please help others find it:  





34 comments




More Articles by - Find me on Google+



Click here to add your comments
- no registration needed!




Wed Nov 30 17:48:52 2005: 1389   anonymous


ooiiooioooil iuoo o iuoi iuuiuiiui100111111 00 1111 00 110001 110001110101 0 100101111 011111111000010111110101



Wed Nov 30 23:13:00 2005: 1392   BigDumbDInosaur


ooiiooioooil iuoo o iuoi iuuiuiiui100111111 00 1111 00 110001 110001110101 0 100101111 011111111000010111110101

Oh no, Tony! Another user with a malfunctioning Windows XP box! Run for your lives!!!



Wed Mar 19 21:46:14 2008: 3862   anonymous


correction: -lm should be written last like this:
gcc -o hello hello.o pi.o -lm

at least for older versions of gcc.



Fri Aug 29 17:31:49 2008: 4516   anonymous


you also could put in the makefile:
all: hello

In that way, you only need to call "make" and not "make hello"
also "clean:" is widely used in the Makefile's, it removes all executales and compiled files:
clean:
-rm hello *.o



Mon May 4 10:40:09 2009: 6312   anonymous

gravatar
hi i have set of .c files and a header and set of dat file i want to make exe out of it please help me!!!!!!!!!!!!!!1






Mon May 4 10:49:48 2009: 6313   TonyLawrence

gravatar
Did you READ any of this?



Wed Aug 5 07:42:39 2009: 6725   innha

gravatar
Thanks for this guide. I learned basic c++ at school and now that i want to know c, i am glad to come across such a clear intro to c.



Tue Sep 8 12:56:07 2009: 6871   CorreyKowall

gravatar
I used C and gcc on Linux as an undergrad and I just started using it again so I used your guide. One very minor complaint, I tried to install lint and found myself chasing down dependencies like Automake and Autoconf for half the morning. Before I finished the process I remembered the Synaptic Package Manager. About one minute after that I was compiling and running Hello World. Perhaps a note about package managers would be helpful.



Tue Sep 8 14:46:55 2009: 6872   TonyLawrence

gravatar
I think you just provided that note :-)



Thu Oct 8 12:27:11 2009: 7136   anonymous

gravatar
C is a subset of C++ so if you learnt C++ you already know C :-S



Thu Oct 8 12:30:34 2009: 7138   TonyLawrence

gravatar
I'd disagree with that - though it depends on what you mean by "know".

I think a person who first learned an OOP language like C++ would have a hard time adjusting to plain old C. Yes, a lot would be familiar, but that isn't necessarily a good thing: that familiarity can lead you to errors and frustration.



Thu Oct 8 13:46:45 2009: 7143   anonymous

gravatar
C++ is C with OOP on top (and some other bells and whistles)

I do agree an OOP to C coder and vice-versa would have a hard time of it !






Thu Oct 8 13:55:26 2009: 7144   TonyLawrence

gravatar
I think it's always harder to go backward.

Think of things like error handling. If you first learned a language that has advanced error handling and then drop back to C, well, you won't be happy and it will be hard for you to code anything because you won't be thinking in C. Your code will suffer and may not even work!

Going the other way, you can ignore most or even all the added features until you need them - your old coding methods will still work.







Mon Oct 12 06:51:49 2009: 7196   yalongxie

gravatar
I'm a c primer,it is very useful for me



Mon Jan 4 08:13:44 2010: 7851   anonymous

gravatar


This was written sarcastically right?



Mon Jan 4 13:09:15 2010: 7852   TonyLawrence

gravatar



This was written sarcastically right?


No. It was written to help newbies understand and avoid the most common mistakes. I guess you never made any mistakes when you learned your first programming language?



Wed Mar 3 05:20:00 2010: 8169   Sikdar

gravatar


Its really helping the students.....................



Sun Mar 7 16:10:14 2010: 8191   PeterRetief

gravatar


Great thanks, I used it to right a basic program for my son to list prime numbers



Thu May 6 05:51:31 2010: 8531   visus

gravatar


hi i wanna know that how can i make my own header file and implicitly use it any program on a gnu c compiler .please tell me whole process using appropriate example .
please do as soon as possible ,i m very curious to know about it.
thank you.



Thu May 6 11:33:47 2010: 8532   TonyLawrence

gravatar


Of course you can:

#include "your header.h"



Wed Jun 16 05:25:53 2010: 8703   anonymous
http://www.dinwal.com
gravatar


Hi,
This is a nice tutorial to learn C. I think for newbies a tutorial that explains Vi editor will be of help too.
Regards,
Dinwal



Wed Jun 16 10:14:00 2010: 8705   TonyLawrence

gravatar


I have a vi primer at http://aplawrence.com/Unixart/viprimer.html



Wed Sep 8 21:58:57 2010: 8963   anonymous

gravatar


As regards to lint under Debian/Ubuntu you can

sudo apt-get install splint

and then just use splint instead of lint



Fri Sep 24 11:50:39 2010: 9001   Ajin

gravatar


Thank for information about how to write a make file.
But it is interesting to know more about it.






Tue Oct 5 10:18:19 2010: 9027   ElijahKeya

gravatar


Good explanation, could you also explain about how to write and complile c++ programs on Linux



Tue Oct 5 10:23:02 2010: 9028   TonyLawrence

gravatar


That's a tall order.



Fri Feb 10 09:44:07 2012: 10589   anonymous

gravatar


hi guys,
i am facing an issue with splint. after running the splint command i am getting the below output.

+++ creating splint report(s) +++
Splint 3.1.1 --- 02 May 2003

Finished checking --- 22 code warnings

it is reporting the 22 code warnings but i am unable to fine the description of those warnings.. please help me out....



Fri Feb 10 13:19:46 2012: 10590   TonyLawrence

gravatar


I don't know much about splint, sorry. Check its manual.

Don't miss responses! Subscribe to Comments by RSS or by Email

Click here to add your comments


If you want a picture to show with your comment, go get a Gravatar

Kerio Samepage


Have you tried Searching this site?

Unix/Linux/Mac OS X support by phone, email or on-site: Support Rates

This is a Unix/Linux resource website. It contains technical articles about Unix, Linux and general computing related subjects, opinion, news, help files, how-to's, tutorials and more. We appreciate comments and article submissions.

Publishing your articles here

Jump to Comments



Many of the products and books I review are things I purchased for my own use. Some were given to me specifically for the purpose of reviewing them. I resell or can earn commissions from the sale of some of these items. Links within these pages may be affiliate links that pay me for referring you to them. That's mostly insignificant amounts of money; whenever it is not I have made my relationship plain. I also may own stock in companies mentioned here. If you have any question, please do feel free to contact me.

I am a Kerio reseller. Articles here related to Kerio products reflect my honest opinion, but I do have an obvious interest in selling those products also.

Specific links that take you to pages that allow you to purchase the item I reviewed are very likely to pay me a commission. Many of the books I review were given to me by the publishers specifically for the purpose of writing a review. These gifts and referral fees do not affect my opinions; I often give bad reviews anyway.

We use Google third-party advertising companies to serve ads when you visit our website. These companies may use information (not including your name, address, email address, or telephone number) about your visits to this and other websites in order to provide advertisements about goods and services of interest to you. If you would like more information about this practice and to know your choices about not having this information used by these companies, click here.

pavatar.jpg

This post tagged:

       - Basics
       - Linux
       - Popular
       - Programming
       - Unix



















My Troubleshooting E-Book will show you how to solve tough problems on Linux and Unix systems!


book graphic unix and linux troubleshooting guide



Buy Kerio from a dealer
who knows tech:
I sell and support

Kerio Connect Mail server, Control, Workspace and Operator licenses and subscription renewals



Click and enter your name and phone number to call me about Kerio® products right now (Flash required)