LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Go Back   LinuxQuestions.org > Blogs > rtmistler
User Name
Password

Notices


Rate this Entry

Linux Set-Up, Write, Compile, & Debug of C Programs for Beginners

Posted 07-14-2017 at 03:43 PM by rtmistler

If you are a beginning programmer and have questions about how to get started, this blog entry may be helpful to guide you. If you already can edit code, compile it, run it, and debug it, then this blog entry is not for you.

This blog entry is not about Windows, MAC, graphical programming, or Integrated Development Environments (IDE).

This blog entry is intended to guide a new programmer to learn how to set-up C tools under Linux, edit and compile code, and how to debug.

Personal Caveat

Yes, this blog entry guides you to become a clone of my way of thinking.

I'm not trying to be maniacal, but instead hoping to give some insight where it may matter. If you are literally thinking of trying programming, and figure it can't be that hard and you can probably master it in an afternoon? This blog will give you some tips, yes you will be able to accomplish programs in mere minutes or an afternoon, however you are not yet anywhere near close to writing a new display driver, or modifying the Linux kernel.

As with anything, you get out of it what you put into it.

Assumptions

You have Linux installed, you know how to use the command line (a.k.a. Terminal), your system is attached to the Internet so as to allow you to download updates, if needed.

Subjects Covered
  • Setting up, or verifying build tools are on your system.
  • Creating that very first C program
  • Compiling the program
  • Running the program
  • Dealing with compilation errors
  • Debugging a program
Setting up, or verifying build tools are on your system

What do you need? You NEED a compiler. You SHOULD have a debugger. You NEED an editor.

Compiler: GCC

At the command prompt, type and hit return after, "gcc -v":
Code:
$ gcc -v
If you have gcc, a few lines telling you the version and more information about gcc will show. If you don't have gcc, then you get an error saying that it is not installed, or not found, or some other variation indicating you don't have gcc.

If you don't have gcc, then you likely also do not have GDB (the debugger).

If you do have gcc, it is likely you do have gdb, but to check is very similar:
Code:
$ gdb -v
Fixes

There is a package, named build-essential which contains gcc and gdb. In which ever manner you can install packages onto your version or distribution of Linux, find out if it recognizes build-essential and then install it.

If your system or the upgrade repositories for your system do not contain build-essential, then try to search and see if there are gcc and gdb packages which you can install. If you get stuck here and cannot solve or proceed, then recommend you open a thread question on LQ in any of the Linux - Newbie, Linux - Software, Linux - General, or Programming forums. You may have an unusual case or a distribution which is not as common as some out there and thus you may need some specific help with getting these tools installed.

Editor: Pick one. There are many. For starters, you likely do have both VI, or VIM, as well as GEDIT on your system. Perhaps also EMACS. I'm not here to recommend one in particular, and do not wish to taint your choice. (COUGH! EMACS ) Get one, or select one, and learn how to use it, OK? And seriously, if you can't do this, it is a pretty big stopping point already. Suggest you do some web searching to find out what editors are there on your system already and what other options you may have.

Creating that very first C program

Open your (COUGH EMACS) editor. Sorry, I have a minor cold.

Copy the text for the well known Hello World source shown here and paste it into your file you are editing. Save that as "a name, with a ".c" extension.
Code:
#include <stdio.h>

void main(void)
{
    printf("Hello World!\n");
}
You can name it "fred.c", "idontcare.c", or "helloworld.c" - picking a name that matches the code contents intentions is probably a good organizational idea as you grow the size of the code you write.

Exit the editor and if you've done all correct, you now have a .c file in your directory.

The sad part

I'm not going to teach you C syntax. Why/Why not? There are plenty of references, please look them up. One contention of mine is that you actually have chosen to undertake programming. Great for you. I'm hoping that you can look stuff up and take both the baby steps of trusting that the provided example is correct, does work, and that you can look up the fundamentals of the C language without me telling you how every little detail.

Compiling the program

gcc is our "go to" program for compiling. Very simply you type gcc, a space, and then the name of the C program file you just saved. Let's say you did choose to call it HelloWorld.c, hence you will type:
Code:
$ gcc HelloWorld.c
It compiles, if you copied the lines of code and saved them correct, it will compile without warning, or comment (likely) and then return you to the prompt, in my example that is the "$ ".

So what did it do? Well, it compiled, it converted that source code into machine language, but binary stuff which you can't easily read, and we're not going to try. But what do you do now? Well, you can verify you got an executable, and then you can run it.

Hopefully you started in a new sub-directory, or one which was mainly empty so that you can see the new files made by you as well as the compiler. Using the ls command with the -l switch will show you files in detail with size, permissions, ownership, and their names. Please try that now.

What you should see are your .c source file, and a file named "a.out".

a.out is the default filename which gcc uses to become your compiled output. You don't have to have it stay this way, you can direct gcc using a switch to name it something else, and you can also rename a.out using the mv command. Notice that a.out has execute permissions, this is what the "x" means in the output of the ls -l command. If you try to cat or look at a.out (excepting with hex dump utilities) you see junk, binary stuff which you can't really read and may also mess up your terminal session because some of the code may be control characters and once they go through your terminal session they may change the terminal attributes, thus making you need to exit that terminal session and open a new one.

Running the program

You now can run a.out. How do you do this? Normally it would be:
Code:
$ ./a.out
Sometimes you do not have to put in the ./ part, this is if you have the current working directory in your PATH variable.

Not-amazingly, you run it and it prints out "Hello World!" and returns to the prompt.

This template is no different for any C program. The variances are if you make mistakes, either in the syntax and have a compiler error, or in the logic and have a code bug which compiles, but does not do what you want it to do.

Dealing with compilation errors

You mess up, the compiler lets you know about it.

Edit the file and delete the semicolon at the end of the printf("HelloWorld!\n") line. This will cause a syntax error in your file that is sufficiently bad that the compiler will give you an error.

Try to re-compile:
Code:
$ gcc HelloWorld.c
HelloWorld.c: In function: 'main':
HelloWorld.c:6:1: error: expected ';' before '}' token
}
^
For the uninitiated this is a lot of stuff, and many new persons wonder what matters and what do they do. Meanwhile, say you have a much larger file with a lot more code lines and a ton of errors, you sometimes see very many error reports, and also warnings. Both are bad, programmers of experience will tell you that warnings are bad and that you should eliminate them. I am of that category.

An aside here is if you check the manual page or help information for the gcc compiler you will find VOLUMES of information about it, about how to use it and about switches you can use. I myself have a sample file which includes the various switches I've added to my gcc compile line over the years to cause it to catch as many warnings as possible and to treat warnings as errors. Which means that even though something is a warning, gcc will not complete the compilation and instead terminate the compile action and not give you an executable file.

An additional aside is that sometimes you can make a fantastic error in syntax, that is so bad that it makes the situation such that the compiler cannot continue parsing the source file correctly. A typing mistake, (we ALL are subject to these) can cause it to end up giving you dozens, or more, error or warning reports, when in reality, you may need to fix a few lines and then all is far, far better.

My points here are that you should not ignore warnings, even if you see some people doing so. A better comment here would be ... ignore warnings at your own peril.

Back to the error you created. The key things are where is says "error", and gives the filename followed by numbers, "6:1". It is telling you that it detected an error on Line #6, Column #1. If you copied the example correctly, this actually is the final "}" at the end of the file, and it also shows this in the error report. A bit confusing because it does not point exactly at the error you created.

To be truthful, I'm going by the seat of my pants here and making this entry as I do the example and verify the steps as I go along. My example error was accidental, in fact a more clean way would've been to do something like, change "printf" to be "paintf" which is not a known function name, and then the error would've been on Line #5, Column #5 complaining that it did not understand what "paintf" is.

I'm rather glad that the original syntax error I chose was somewhat misleading. It illustrates my very exact point that the error report is not always exactly where the error resides. As a deeper thought, let us say that the C file had a lot more code following that one printf() statement. Well, the complaint, or series of complaints may be all a result of that one typing error. The programmer who takes the time to think will look at this, they'll know that a close bracket "}" is not a bad thing, unless you have an extra one, or are missing one. They'll also look and pretty quickly realize that they left out the semicolon in the line before the complaint.

(So now fix that semicolon problem and change the spelling of printf to be paintf ... examine the syntax error report there.)

A confusing thing here is ... a.out is still there. Why? It never got replaced, you edited the source file, made some errors, and it never happened to remove the old a.out file. The original code you compiled into binary, still has a binary because you never got far enough compiling a second time to create a new a.out file. You can verify this by doing the ls -l command and examining the date and time of the files in question. This is more important as you progress. Also potentially tied to warnings. Many programmers do ignore warnings. They've seen that sometimes, or many times, the warnings are benign, they've never yet been bitten by the few that really do matter, or a test case which matters, so they learned to not care. Further, sometimes people compile a number of files together, usually using a Makefile (not discussed here), however what can occur is screens' worth of output with the compilation, warnings or not, and since sometimes it is a lot of stuff, sometimes a new executable file may not be created, but the fast moving programmer may have not noticed. It is very common for someone to change "one thing", they KNOW they did it right, don't EVER tell them they typed one lousy word incorrect! They re-do their compile, it streams a lot of stuff on the screen, they don't really look at it, and then they run their executable. In those cases, the executable is the OLD one, they didn't yet notice. Eventually they may find that they are expecting that bug they fixed, or that small change they made to be present and they're sitting there inexplicably trying to figure out why this lousy computer is not obeying!

A lot of that is where this subject is not for the faint of heart, or those who wish to snap into the subject for an afternoon, rewrite an entire operating system, and feel that this is "no big deal". Suddenly, nothing is working, you are moving far too fast to really see why, and when these types of things happen, many of us with experience know that it only goes downhill from there. I've been there and hopefully will not be there, or so badly there again. Yes, I will make coding errors, I will make syntax errors, I will get mad, and I will rush. Hopefully I'll reduce my anger and frustration with my experiences, and memory.

Syntax errors, warnings, and bugs/defects

There are differences. Syntax errors stop you from compiling and building your code into an executable. Warnings do not always stop you from completing your compile and getting an executable. Warnings do not always cause bugs. I still say that you should aim for warning free code. Bugs or defects (same thing, different names - and there are likely other names) are actual problems which may not be syntax errors. Please understand that it is perfectly fine for code to compile, but yet not work correctly, or even worse, to have a fatal error. If you try to access a bad address you'll encounter what we call a "crash", a fatal exception. This fatal exception will actually occur during program execution. NOT during compile, and not always every time you run the program. It may have to do with the conditions. Such as "changing past midnight" - the time goes from 23:59 to 00:00 and suddenly code faults. Or maybe it is a program where someone is supposed to enter a username, and instead of doing this, they just press enter. And as a result, there is "nothing" put into some code, eventually it may run into a fault perhaps because it never took into account testing for that "nothing". These are bugs. The code written to accept input may have been written "syntactically correct", which is the same as "grammatically correct" for something like a language. But it doesn't mean that the code will work correctly.

Debugging a program

So what do you do when you have bugs? You DE-bug. I have to say that I probably have done this for 30 years and never really thought about the coining of that phrase and how apt is it to this description.

GDB, introduced in the first section is a debugger. The act of debugging, to me, is really analyzing, running, single stepping through the code, adding debug output statements, and other various techniques in order to find and remove the actual bugs within the code logic. Oddly enough I've always thought of the debugger as the thing I use to find the bugs. But now realize that the whole purpose of it, as well as the name, really is to DE-bug ... a.k.a Remove the bugs. (Example of how we learn everyday! )

The subject of debugging is very complex. Many times debugging is quick, you do it, don't even need to use a debugging application like GDB, and you are done. However, if you end up writing a lot of programs over many years, or get paid to do this for a living, you need to learn some techniques and improve your efforts both with coding correctly, as well as debugging effectively.

This is one of the reasons why "I" say to strive for warning free code. It's just one more thing you do not wish to have in your way or allow you to have a potential bug because you overlooked something that the compiler can help you catch.

Fundamental examples:
  • A switch statement missing a default case
  • An implied cast of a variable
  • A precedence error
I do not expect you to know those terms and explanations.

A switch statement tests various "cases", one "catch-all" case is actually named "default". If you do not have one, you do nothing about it, however perhaps you really do need to do something about it. This is also similar to an "if" statement missing an "else" clause. It tests "if something matches the test" then it does the actions when it passes the test. When there is no "else", the things which do not match the if test just get nothing done. However you instead may wish to treat all conditions where the if test fails in a very certain manner, but ... you did not code an else clause.

An implied cast: Say you call a function which requires a certain sized variable, but you have a larger sized variable and you just pass that to the function, once again ignoring any potential compiler warnings. Perhaps this cut-down variable is interpreted incorrectly? Well ... it's a bug.

A precedence error: There are rules of precedence in the language. There were rules in Math that you learned in Junior High or maybe even grade school, and you also learned that parentheses force groupings to be how you want them to be. Anyone remember or ever hear of "Please My Dear Aunt Sue"? Parenthesis, Multiplication, Division, Addition, Subtraction. That's a traditional Math precedence. Sorry, U.S. based, that's one thing I learned and retained. Yes I have other ones, perhaps a more "fun" blog about shortcuts.

I'm going too far and writing too much at this point, and very fortunately for me, a few years ago, I already made a blog entry about debugging in C using GDB, as well as some suggestions for defensive coding.

So glad I did that, I can stop here, give you the link, Debugging C Programs Using GDB (Including core dumps!) and rest my fingers.

Follow-Up

Nothing here except closing thoughts.

Eventually things get old and last for years. (Such as me)
That blog on debugging is a few years old and just today I noticed that some people had offered comments for I allowed comments to be moderated by me prior to posting. Wow ... I finally approved those comments from over many years' time.

What else? Coding can be fun, it can be easy and it can be hard. All of what I've written here is more for someone who actually wishes to code a lot, not just play around with it for a brief day or so.

Enjoy! Happy Coding!
Views 1230 Comments 0
« Prev     Main     Next »
Total Comments 0

Comments

 

  



All times are GMT -5. The time now is 01:33 PM.

Main Menu
Advertisement
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
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration