C – an overview.
C is a great, if complicated language. It’s simple, yet can get complicated very easily if you don’t have a clear idea of what you want to do with it.
Lets get into it then.
The way C works is you write your code in ‘real language’, i.e. into a word processor type app, then you save the file, and give that file/s to a compiler that converts your ‘real language’ commands into straight assembly language. It can do it one of two ways. The first is a literal translation of your instructions. Thus the object file that it creates (object is what the compiler creates, source is your original code – you’ll see these two terms everywhere) is as close that the compiler can get to your original code. If you use three variables in your code, they are there present in the object code. This is called Debug mode.
In Release mode, the compiler takes short cuts with your code, and does something called “optimization” to it. In this case, although your code may have three variables in it, the optimizer might say, “I can do this command with only two variables, and since it’s going
to be faster that way, I will”. This is great, and your code should run and end up with the same result as in debug mode. But it makes debugging the code a real pain since the object code really doesn’t look like the original code you wrote. Sometimes you can’t see variables, or on occasion the compiler may just remove a procedure entirely, which is really scary.
Anyway, you only use release mode once you are confident you code works correctly. It typically gives you about a 10% to 50% speed increase depending on what you are doing. BEAWARE that sometimes the optimizer can make mistakes. We’ve seen it here, and there is nothing worse than trying to find an optimizer bug in the code at 4 in the morning. Test your code in release every so often, so if there is one, you’ll know what you just added, so you know where it is likely to be.
Ok, C structure. The code it self is made up of .c files, with the code itself in it, and .h files. .h files are for your data definitions and external prototyping. Don’t worry about what that actually means, you’ll understand later.
What you generate are usually .exe files – stand alone executables.
There are two other types of object file you can build with all PC compilers. .lib files and .dll files. They two types are actually very similar, just at different stages of the compile pipe.
To explain, here I am with my clever project that does something to .jpeg image files. It loads them in, does something to the image, and then saves them out again. Now jpeg compression and decompression is a tough thing to write. I certainly don’t want to do it. However, others out there in the world have already written libraries to do it. I have three choices how I can use their code.
I can physically include their .c and .h files into my code base, and compile it all at one time.
I can use a .lib file (usually provided by them) and link that into my project.
Or I can use a .dll (a dynamically linked library) at run time.
A lib file is basically a precompiled set of .c files that is ready to be linked into your project. It’s a black box, and comes with a set of prototypes for the functions contained within. You don’t get/need the source code, you just a .lib file to link in, along with definitions of the functions within the .lib file, how to call them, and what to expect once the code returns. It’s like a cd player in a car. The car doesn’t care what the CD player is, it just provides some standard cables to link it up. You can replace the CD player with another one, and the car doesn’t really give a s**t.
The disadvantage of using a .lib is that often you can’t debug it if it does have bugs. Since it’s already compiled code, your stuffed, since you can’t see inside it.
The advantage is that there are tons of libs out there, and once you’ve used the lib, it’s there anytime you ever want to use it in another project. It’s just black box code that you know works.
A Dynamically Linked Library is very like the .lib files above, except it’s not compiled into the project. It’s loaded at run time, on the fly. You create your project, and you put some code into it so that at initialization it will load “jpglib.dll”, which provides you with access to a bunch of jpeg functions. The windows operating system provides you with access to the functions through some cleverness we won’t get into here.
DLL’s are great for replaceable and sharable functions. Want to use the same jpeg functions as are available in Photoshop? Simple, use their jpg.dll –assuming you have it on your system. You see in installs that sometimes windows come up and say “This DLL is not shared –delete it?” this is the registry saying “well, this program installed this DLL, and no one else uses it according to the registry, so I guess we can delete it. If it IS being shared, it won’t let you delete it, since someone else needs it”. It’s also great because as long as the input/output requirements of the DLL remain constant you can upgrade the DLL many times without having to rebuild the original project at all. You can add to a DLL, but you can’t take away functions, since that will break it when it’s loaded by the main program.
There are the same disadvantages for dlls as for .libs. And further disadvantages are that you can never assume a DLL is already on a windows system. You always have to provide them with code install.
And of course, DLL’s are only on windows machines. Linux has .so files, which are similar in intent, but different in implementation.
And Macs have nothing remotely like it. So if you intend to write portable code across systems, don’t rely on .dll’s.
Ok, C is a structured language. That means that you are supposed to structure your code so you can drop and replace modules easily.
It’s all based around procedures. Here’s an example one
void main (void)
Don’t worry about what printf or the void or any of that stuff means, that’s not important. What is important is that you note that all the code is contained within the curly brackets, and that before that, the procedure is defined with what variables are being returned, a name, and what variable we should expect to be sent with a call to this function.
The function ‘main’ is always the first function that is ever called in a c program; it’s where execution starts. Unless you are writing windows functions of course, Microsoft just HAD to be different.
Anyway – This is all covered in greater detail later.
The idea of C is that the language allows you go to the lowest levels of the machine, actually talk to specific registers and memory addresses, yet be high level enough to create code that is portable and can be reused in other projects, and even across different machine types. The most basic definition of C is ANSI C. Almost every compiler out there subscribes to this definition. It’s not like the old BASIC used to be, with the same core everywhere, but different extensions. C is much more the same across platforms. One of the drawbacks though is that because C allows you to talk to the metal (which means you are talking to a specific aspect of the platform you are on – but which isn’t shared by different platforms), often you do, and your code is then not transferable across machines. To combat this, you should write code in a modular fashion, so that when you transfer your code from the PC to a Mac, you can simply drop this, this and that module of code, and re-write it for the Mac specifically, but the rest of the code should run exactly the same.
Now C as a language provides you with everything you need to start creating from the word go. However, there are a ton of features that are also provided as standard across different implementations of C. While you could write your own file manipulation routines yourself, why bother?
When you install a C compiler on your system, you also get a bunch of source code that the compiler will automatically use for you. For instance, if you include the “stdio.h” defines file in your project somewhere, the compiler knows to go away and find the source code that goes with it, and build it into your project. Then all of a sudden you have access to a bunch of file manipulation routines that ARE THE SAME ACROSS ALL COMPILERS AND PLATFORMS.
So if you write your code right, you’ll get the same results if you run your code on a Mac, a Linux box, a Playstation or a PC. Nice:).
What’s provided is also defined by the ANSI standard, you get string manipulation routines, math routines, file routines and so on and so on. At some point you will need a good reference book that will detail all of these functions that are available to you. Right now though, I will tell you about what you will need to start out.
Then of course there is C++. This is to C what a full French language course is to a French phrase book. C is very powerful, but it’s deliberately made with some loose rules. C++ tightens the rules a lot, but also provides a ton of more modes, and pre-written code, along with a bunch of new data and code structures. C++ is more a frame of mind than anything, but it’s way beyond what we need to be covering right now.
Incidentally, we aren’t getting into Windows type programming right now since that’s pretty much all C++, and we need to walk before we run.
Stick around and we will get there though.