Wednesday, 26 September 2012

C on Linux Kickstart

Overview


So, there are plenty of resources for learning how to program in C/C++ (see the end of this post) but here's a quick guide on how to get off to a good start with the practical matters. It's the sort of stuff I wish someone had pointed out to me when I started, since it would have made my life a lot easier.

While graphical IDE's may make your life easier for large projects, a knowledge of how the core tools used in making programs fit together is essential if you're going to go anywhere with your programming; where more complex tools let you down, you can pick yourself up if you know what they're doing behind the scenes. This is why this guide will start you off using the compiler on the command line.

The command line


If you're not already used to using the command line, have a look at this chapter of Introduction to Linux: A Hands On Guide. You'll need to get comfortable with moving around the file system, creating and listing the contents of directories, etc.

What to use & install


The two absolute essentials you'll need are (i) a text editor and (ii) a compiler. You might already be a fan of the text editors vi or emacs, both popular with programmers, but they can have a steep learning curve. If you've got a graphical Linux distribution it will have a default text editor that will doubtless have syntax highlighting (this makes certain parts of your source code stand out). The defaults for Gnome, Kde and Xfce are gedit, kate and mousepad respectively. So from the command-line, you can open e.g. the file program.c from a Gnome desktop by typing the following at a terminal:
    gedit program.c
As for a complier, by far the most popular option is GCC. On Debian/Ubuntu, you can install this, as well as all the development libraries you'll need, by installing the build-essential package (as root):
    apt-get install build-essential
On Fedora/Red Hat, the same effect can be achieved by:
    yum groupinstall "Development Tools" "Development Libraries"
If you have another distribution and you're not sure what to install, ask around; if you can compile the main.c program in the next section, you have what you need.

How to compile programs


To give us something to work with, open your text editor of choice, write the following into it (copy & paste if you like/you get errors) and save it as main.c:
#include <stdio.h>

int main()
{
    printf("hello world\n");
}
We won't go into what the statements mean (I'll leave that to the tutorials at the end of this post) but this gives us something practical to work with.
Now, you can't run this file directly, you first have to compile it into a file that you can. The simplest way to do this is:
    gcc main.c
This will produce a file called a.out. You can run this in the usual way (from where you are just after compiling, type ./a.out). If you like, you can specify the output file to be something different by using -o filename (e.g. gcc main.c -o main).

However, you will make your programming life easier if you never compile your programs like this; it will lead you down a bad path. When you compile programs like this, you will let GCC ignore many potentially dangerous practices. Luckily, GCC has a way to alert you to these in the form of its warning options - they control what situations GCC will warn you about, and what situations it will silently ignore. The defaults are pretty lax, and while they may be useful in compiling legacy code you know to work and just want to compile, when learning and/or writing new code, you want your compiler to be as strict as possible. There are an endless variety of options you can fine-tune this strictness to your heart's content if you like, but for now there are three that will serve you very well: -Wall, -Wextra and -Werror. The first two of these enable a group of common warnings, and the last turns all warnings (that would usually just cause the compiler to emit a message about the offending construct) into errors that cause the compiler to flat-out refuse to finish compiling your program until you've sorted the error out.

These warnings are there for a reason; use them. They will prevent you from making mistakes that will lead to bugs that will just needlessly waste your time. A quite common forum post from new programmers reads essentially "here's a program that doesn't work the way I expect - help!". At least 50% of the time, I can copy + paste the program and compile with -Wall -Wextra and the result will tell me what they've done wrong, without even having to look at their program. Why spend time searching for errors when you can let your compiler do it for you?

In short, always compile your programs with at least -Wall -Werror - try it now with our main.c above:
    gcc main.c -o main -Wall -Werror
You'll notice I've not included -Wextra in the above command-line. -Wextra can be a bit harsh, especially on new programmers; use it to double-check a program that's not behaving as you expect, or for any code you hope to give to others (including posting it on a forum) for a thorough sanity-check first.

Dealing with error messages


There is one golden rule when dealing with error messages. At first you (like me) will probably ignore it, only to learn through bitter experience that it applies no matter how experienced you are. Luckily, it's very simple:
  • Always deal with the very first error message emitted by the compiler.
The reason for this is quite simple: once the compiler sees something wrong, it's very likely that later things will make even less sense to it than they ordinarily would. So find the first error the compiler spots, fix it, then try recompiling. Often you will fix several error messages by fixing one actual error.

The error messages emitted by GCC are always in the format file:line[:position]: ERROR MESSAGE. If you've tried compiling the above main.c with -Wall you may have already seen the following:
    main.c:6:1: warning: control reaches end of non-void function
This lets us know that the error occurred in main.c on line 6 (and was estimated to be at character 1, but that's rarely useful). Exactly what this means you'll learn in time, but in this case we can fix this by turning main.c into:
#include <stdio.h>

int main()
{
    printf("hello world\n");
    return 0;
}
Try recompiling and you'll see no error message.

When you see an error message you don't understand, don't ignore it or start turning warning options off until it goes away. A quick copy-and-paste it into Google (leaving out any specifics like file names, function names and line numbers) will usually tell you exactly what's gone wrong:
    main.c:6:1: warning: control reaches end of non-void function

Where to go from here


There are several good introductions to programming in C on the web, my favourite being this one.

When you get stuck, forums can be invaluable - there is a Linux-specific forum with an active programming section here, and active forums for C and C++ programming here and here, respectively. You'll get good, fast responses if you include (i) code that demonstrates the problem you're having, (ii) what you think the code should do and (iii) what's going wrong.

No comments:

Post a Comment