Programming by James S

Introduction

On this page I will help you with programming using C++ and other programming languages, but first just a little bit of background information about my programming experience. I have programmed as a hobby for many years on different types of computers using BASIC, assembly language, C/C++/C# and Python.

I used to use QBASIC which came with versions of DOS which was good but the best version is Visual BASIC, also by Microsoft, and runs on Windows. BASIC is fine for beginners and for performing simple tests but it's often not advanced enough or fast enough to create software such as a game.

I have done assembly programming on a 6502 CPU using microcomputers, on the 68000 processor using the Amiga, on a Z80 CPU using a TRS-80 and the MIPS processor used in the N64 (some of my more advanced game codes are actually short programs). Assembly language gives you great control over the hardware and some time ago it was the only option for creating some types of software. But now I use it a lot less since it takes longer to make programs with and you are more likely to make mistakes. However, a time when I still use assembly language often is when programming PIC microcontrollers (although other people prefer to use other programming languages).

I'll admit that I wasn't that keen to try out C++ although I knew it was about the best to use between BASIC and assembly language. But at the time I got myself a Borland compiler that was designed for Windows 3.1 and 95 but amazingly I have got it working on Windows 98, 2000 and XP (not in compatibility mode!). I now know C/C++ very well and have written all sorts of programs using it including games and utilities.

Then there came a turning point for me; I had used the Borland compiler to program 2D games that used DirectDraw and wanted to move onto 3D yet there was the worry that I would have trouble getting Direct3D to work on the Borland compiler. I thought to myself that if any compiler should have no trouble with DirectX it should be a Microsoft compiler. So, almost with a tear in my eye I said goodbye to the Borland compiler and hello to Visual C++ (actually I still used the Borland compiler for a while on another, older, computer of mine).

I wouldn't say that I made a mistake in downloading Visual C++ especially as it was the free version but it has been quite a pain to use. I like the compiler, particularly its ability (most of the time) to help you out by providing a list of member variables and functions that belong to a class and its IDE has been done well. But I have had many errors when using it thanks to its strict version of C++ and due to the support for managed code. I'm now writing programs which mainly use managed code as in theory that should mean better programming and less chance of errors (such as memory leaks) but it requires that you have the .NET framework, something to remember if you give a managed program to someone else to try out.

As for Direct3D it worked with Visual C++ but I had much trouble getting it to work, and ended up settling for a slightly lower version than what my system was capable of (which wasn't a totally bad thing). And I ended up mixing native and managed code just so I could actually get on with programming my game.

Number systems

It's not surprising us humans are used to using the decimal number system (sometimes called denary) which uses the numbers 0 to 9, as we have 10 fingers in total (8 fingers and 2 thumbs to be technical). But computers, at low level, use binary, which consists of only the numbers 0 and 1. While this may seem very limiting, because computers only have to deal with a lower range of values it greatly simplifies the storage and handling of numbers. By grouping these 0's and 1's together, however, very large numbers can be formed.

Bits, nybbles, bytes and words

Computers store data in bits (short for binary digits) and each bit can store a 0 or a 1 (like a light switch can only be off or on); this is an example of digital representation. A group of 8 of these bits is usually known as a byte but sometimes a byte may be larger (e.g., a 16 bit byte) - I think it's best to stick to 8 bit bytes. However, where there may be confusion, the term octet is sometimes used to mean 8 bits and in fact, in some languages (such as French) octet is used instead of byte. Byte, is actually a misspelling of bite so that it doesn't get mistaken for bit.

Half of an 8-bit byte, that is, 4 bits is known as a nybble (sometimes spelt nibble) or a semioctet. The term word is often used for a larger group of bits such as for 16 or 32 bits. It all comes down to what CPU is used and the naming convention associated with it.

Binary values

Each of these bits has a certain place value, or weight, as is the term sometimes used. If we look at the decimal number:

516

You know immediately what value it is but let's break it down into individual parts. The '6' is in the units (1's) column, the '1' is in the tens column, and the '5' is in the hundreds column. So in fact what we have is:

(5x100) + (1x10) + (6x1) = 516

Binary is not much different, it just uses a different range of values. Here is a binary number:

101

The above binary number is actually '5' in decimal. Each bit (0 or 1) has a place value starting with 1 on the right, then 2, then 4, doubling each time. It will become clearer if we look at the binary number again but with the place values in bold:

4 2 1

1 0 1

So now you can see:

(1x4) + (0x2) + (1x1) = 5

It will help very much if you have a go yourself trying to convert from binary to decimal and vice versa. What helps is if you write out the place values for a byte as follows:

128 64 32 16 8 4 2 1

Then you can write out the binary values underneath such as:

128 64 32 16 8 4 2 1

1 0 0 1 1 0 0 0

Simply add up like in the example and you will get the decimal value. Can you work out the highest value that can be stored in a byte?

Each of these bits, as well as having a place value, also has a bit number (in bold) which are as follows:

7 6 5 4 3 2 1 0

128 64 32 16 8 4 2 1

Below each bit number is the place value. So, the first bit is number zero, the second bit is number one and so one. Starting with zero for the first bit number may seem strange but it actually makes sense form a mathematical point of view. In the following, two (binary is base two, remember) is raised to the bit number (in bold) giving the bit place value:

2 ^ 0 = 1

2 ^ 1 = 2

2 ^ 2 = 4

.

.

.

2 ^ 7 = 128

If you wanted to work out how many values can be stored in a group of bits simply use this formula:

2 ^ n

Where n is the number of bits. So, for example, if there were 8 bits:

2 ^ 8 = 256

That is, 8 bits (a byte) can store 256 different values which are 0 to 255.

Bit zero, with the place value of one, is the least significant bit and the bit on the opposite end (bit 7 in the case of 8-bits), with a place value of 128, is the most significant bit.

Hexadecimal

Binary is all very well if you are a computer but generally humans like to work with something a bit more manageable than strings of 0's and 1's. Of course there is decimal but there is also another widely used number system in programming called hexadecimal, or hex for short. Hex uses 16 symbols, 0 to 9, and then A to F for 10 to 15. So, for example, C in hex is 12 in decimal.

Here is another hex number:

3B

The place values for hex start with 1 on the right, then 16, 256, 4096 (multiplying by 16 to get the next place value) and so on. So, the above example is converted to decimal like this:

(3x16) + (11x1) = 59

(Remember that B in hex is 11 in decimal.)

Below is a hex chart which you can use to convert between hex and decimal and between decimal and hex. Say we wanted to convert the hex value 67 to decimal; find the first digit on the left (6) and then look across to the column of the second digit (7). You will find that 67 in hex is 103 in decimal.

To convert a decimal number to hex first find the decimal number in the grid, for example, 141. Look left at the row numbers for the first digit (8) and then back to the decimal number find the column value (D). So 141 in decimal is 8D in hex.

You can also use a calculator, such as the Windows calculator, or certain handheld calculators to convert between different number systems. For the Windows calculator you will need to change the view to 'Programmer'.

Here is another chart you may find helpful which shows the binary and hex equivalents of the decimal values 0 to 15; the complete range of a nybble. This chart can also be used for converting much larger numbers. For example, if you had the hex number A4 and you wanted to work out the value in binary all you would need to do is put together the binary values for A and 4:

A (hex) in binary = 1010

4 (hex) in binary = 0100

= 10100100 (binary)

Hex is very useful, for one thing it takes up a lot less space for the equivalent in decimal or binary (which makes it very handy for hex views of data such as memory viewers). For example, the decimal number 255- the highest value that can be placed in a byte- is FF in hex; 1 less digit. Also, each hex digit represents a nybble (4 bits), and all hex symbols (as well as decimal and binary values) can be shown on a 7 segment display (like the type often used in alarm clocks). This was more important in the earlier days of computers as back then they had very limited forms of output. However, even today there is a sort of equivalent in that programmers sometimes write a hex string, such as DEADBEEF, to memory so that when viewed by a software application that displays hex numbers they can see that that particular memory has some significance (such as unused memory). This is making use of hex numbers using the letters A to F and is known as hexspeak.

Ordering of bits and bytes

Going back to binary, you may be wondering why the first bit value (least significant) is on the right and not the left and it is mainly because of tradition. They could be labelled the other way round but it is best to stick to the usual way as, you are about to see, we have to worry about the order of bytes.

It depends on the CPU the order that bytes are stored and this is known as the endianness. For example, if you look at the following hex value:

2C34

If we were using little endian then the 34 would be the most significant byte but with big endian the 2C would be the most significant byte. So, little endian means that the little (least significant) byte comes first but with big endian the big (most significant) byte comes first. Here is a summary:

Little endian LSB MSB

Big endian MSB LSB

Most CPU's will either use little endian or big endian but some allow the selection of the one you want to use. In case you are wondering where the term 'endian' comes it is actually from the book Gulliver’s Travels in which there are one group of people that break open their eggs at the small end (little endian) and another lot of people that crack open their eggs at the big end (big endian). This idea of which end something should be done made its way into computing, as previously described.

Specifying the number format

It is very important to know whether the numbers you are working with are in binary, decimal or hex. For example, have a look at this number:

10

Is that a binary, decimal or hex value? It could be two (binary), ten (decimal) or 16 (hex).

To specify what format a number is in, usually a prefix (a symbol before the number) suffix (a symbol after the number) is used. Common types and examples of prefixes and suffixes are given below:

b11000010 (binary)

h30 (hex)

0x12 (hex)

d675 (decimal)

F1h (hex)

$45 (hex)

%00010110 (binary)

#FE (hex)

And there are many more. What is important is that you have a way of knowing the format of the number and when it comes to programming the computer knows the format (although there may be cases where it will only accept one format). Note that if there is no prefix or suffix it is sometimes safe to assume the number is in decimal format but it is always best to specify the format if possible.

As well as specifying the number format of a value, numbers also need to be spoken correctly to give indication as to the number format. For example, whereas we would read out the decimal value 10 as 'ten' if it were the binary value 2 or the hex value 16 it would be wrong to speak it as 'ten'. Instead, a binary or hex value should have each digit read out from left to right, as in 'one zero'. You could always say 'binary value' or 'hex value' before reading out the digits.

There is a very common saying that goes:

There are only 10 types of people in the world: those who understand binary, and those who don't.

The above saying relies on the fact that most people, especially non-programmers, will assume that the value '10' is the decimal number ten when it is actually the binary value two.

Bit flags

Although we often treat groups of bits as having an overall value, often they will be looked at individually like we did to learn how they work together. When we use each bit separately they are often known as flags as they can be used to signal a certain condition. For example, one bit could be used to signal an error if it has the value of one or no error if it has the value of zero. Another bit may represent some other condition such as if a certain feature is enabled or not. In this way, conditions can be stored together but can be used individually, combining together the bits.

Negative numbers

What about negative numbers you may ask. The common approach is to use the most significant bit as a flag that determines whether the number is positive or negative. When this bit is equal to one it signifies that the number is negative, when it has the value of zero it means the number is positive. The downside of this technique is that you can't store as many positive numbers. For example, in 8 bits, you can store 255 positive numbers (1 to 255) and zero; this is known as an unsigned byte. Contrast this to storing both positive and negative numbers in 8 bits-known as a signed byte-you are able to have 127 positive numbers, zero and 128 negative numbers.

Programming vs. scripting

While programming and scripting can sometimes be used to mean the same thing there are a number of key differences. Programming is the set of commands that is used to make complete programs which run on a computer or similar system. Scripting, however, while similar to programming, generally allows extra functionality to be added to an existing program, behaving like an add-on to the main program.The script is usually written in a simple language which the main program understands and uses.

Let's use the example of a video game. There will be a huge amount of code that runs the video game and is probably written in C++ or something like that. When changes need to be made to the way objects behave, or how AI responds, etc., that requires that the main code be changed. This is very time consuming and is not friendly for designers who are not so good with programming complex languages. By providing support for scripts the game can at run-time read through the script and performs actions, such as to place an object at a certain position or to set the weather, to build levels or set certain behaviour. So while the script won't be compiled like most programming languages are they do allow for big changes to be made to software using a simple language that is more friendly to users.

Debugging

No programmer is perfect and so there will be times when errors will show up while your program is running. Some problems can be fixed without much trouble but others will require debugging as to spot the mistakes in the code.

If you have a good idea what part of your program causes the error then you can set up a breakpoint which will pause your program at a particular point in your code (where the breakpoint is placed). When this happens you can then examine the state of the variables and step through each statement one at a time to more clearly see how your program behaves. Note that while you can have more than one breakpoint set at a time, there are certain places you cannot place a breakpoint such as where no code is generated (e.g., a comment).

Typical compilers offer several options as to how to carry on execution of your code when a breakpoint is reached. The key difference between the step over and step into options is that step over executes function calls as if they were a single statement but step into lets you step through each statement of the called function. You can also choose to continue program execution until a breakpoint is reached again of stop the program completely.

Having a two monitor set-up can help with debugging in that you can have your programming IDE on one monitor and your program running on another monitor. In this way you can see your code and set through without having to keep switching between different windows.

Code management

When you first start out writing simple programs there will probably be not too much worrying about how your program looks or runs-most people start with displaying the text "Hello world!". But as your code gets more complicated you may find it more difficult to fix errors or even to remember what it is your was trying to do, never mind allow anyone else to work out what is going out.

May I stress the importance of commenting your code, which in C++ is done with the '//' or the '#' in Python, to give some examples:

//This is a comment

#So is this a comment

Even short comments can be a great reminder of what your program does, what inputs it takes, and so on. At the start of a program I have a header such as:

//LCD driver

//Communicates with a HD44780 LCD

//Version 1.2

//By James S.

Straight away you know what the program is to be used for, the version number and the person that wrote the software.

Other keys places to put comments, other than on individual lines of code, are in functions so that you can detail the input(s) and return value(s):

bool updateTask(int value1, int value2) //Update the current task

{

//Input param(s): (int) value1: the first value

// (int) value2: the second value

//Returns: (bool) false if error trying to update; true if update completed

...

}

As your functions get longer it's a good idea to break down your functions into additional functions that are called from the main function:

void update()

{

//Main update function

getInput(); //Get input from the user

processIP(); //Process input from the user

drawFrame(); //Output current frame to display

}

Not only does the above look easy to read it is also simple to disable a function call (by putting a comment '//' before the function name) and you can reuse the code no problem just by calling the sub function.

Another way to break down your code into more manageable parts and make it easier to reuse your code is by making uses of classes. While I won't go into a lot of detail about classes here I will go over the basics. Let's say you are programming a video game which can be broken down into the following elements:

Input

Process

Display

Audio

With a simple game you could probably fit all of the code for the above in a single file but what about if you wanted to reuse some of the code in another game? Well, classes let you group related data and functions into one place (a file) and also make sure that the data is protected. When you start out in coding it can be too easy to use global variables which can easily get modified and make debugging difficult. Classes, however, encourage data hiding-only letting functions access data that really need to.

Classes are only templates but once class instances are created ('living' versions of the classes) they can be used in your program and each class instance gets its own copy of the variables but share the same code. For e.g., if I had a class called Person I could create multiple instances of Person and assign them individual values (such as age, gender, and so on). Functions of the class Person could be sleep(), eat(), read(), etc.

Common tasks

Here I will talk about programming common tasks needed to do by a typical program, and how to do them using Visual C++ and managed code.

Colour Palette

When most people think of a colour palette of the computer type, Microsoft's Paint program usually pops into their head. You too can have your own colour palette in your application without much effort. Just read the following which is for C++ programs using .NET framework:

Add to your program's form a ColorDialog component from the toolbox- note that it will appear in a separate section from the form-and be sure to name it something sensible such as colours. To get it to show up while your program is running, use the ShowDialog() member function:

colours->ShowDialog();

The user can then select a colour but you will need to check if he or she actually clicked on OK, using code such as:

if (colours>ShowDialog ()==System::Windows::Forms::DialogResult::OK)

If the user did click on OK then you can get the colour that was chosen, so for example, you could assign the colour that was picked to the form's background colour:

this->BackColor=colours->Color;

Solving Common Errors

Visual C++ Catastrophic Failure

Error: When you are using Visual C++ and you try to load the form designer you get the error Catastrophic Failure...

Solution: Delete the intellisense file for your project and then reopen the form designer.

Label Does Not Update (.NET framework)

Error: ToolStripStatusLabel text doesn't update while the application is doing heavy processing.

Solution: After changing the text of the ToolStripStatusLabel, call the Refresh() method of the StatusStrip component that owns the ToolStripStatusLabel.

Note: this may work for other components as well.

Error: An unhandled exception of type 'System.StackOverflowException' occurred in System.Windows.Forms.dll (.NET framework)

Solution: There are multiple causes for this error but one reason is if you alter a component's checked property during the checkedChanged event. What happens is that by changing the checked property it triggers the checkedChanged event again and again until the above error shows up. If you need to change the checked property don't use the checkedChanged event and instead use the click event where the checked property can be altered.

Use of macro gives odd result

If you are using C++ or C# generally const should be used for constants but unfortunately some people use #define, especially in programs written in C. You have to be very careful of macros which involve some kind of formula as they can cause odd results. For e.g., let's say we have the following:

#define THIN_WIDTH 12

#define WIDE_WIDTH THIN_WIDTH * 2

This gives us 2 macros; THIN_WIDTH gives us the value 12 and WIDE_WIDTH takes on the value 24. It would be perfectly fine to use one of the macros as part of a calculation such as:

int result = 48 / WIDE_WIDTH;

You would expect the variable result to have the value 2 but in reality the result would be 8 and this is because WIDE_WIDTH gets replaced with THIN_WIDTH * 2 before compilation so the actual calculation becomes:

int result = 48 / THIN_WIDTH * 2;

Division takes place first so the first part calculated is 48 / THIN_WIDTH which is 4 which then gets multiplied by 2 ending up with 8 as the final result. A solution, other than to not use macros for constants is to enclose the macro as follows:

int result = 48 / (WIDE_WIDTH);

Which makes sure 48 is divided by 24 and not 12. If the macro was declared in someone else's source file you could assign its value to a constant:

const int wide_width = WIDE_WIDTH;

Then you could do:

int result = 48 / wide_width;

Undo/redo

Programs often feature some form of undo and redo options which let the user effectively move back and forward in time. Depending on the type of data and the operations that your application offers will affect how undo/redo are handled. For e.g., with a text editor you could make a copy of the entered text and then restore it when the undo operation is selected. However, this would require a lot of memory so it would probably be better to remember the user's actions (e.g. a word was typed) rather than making backups of the entire text.

Some programs display the history of actions and let the user jump forward or back by clicking somewhere in the list (all actions up to the point you clicked would be undone/redone). But even without that, it's a good idea to at least tell the user what action is the current one to undo or redo. You could do this by displaying in your program's edit menu the name of the operation, such as 'Undo new object' or 'Redo edit name'. This is what I did for my video game, which I'll describe in the following paragraphs.

I used a list (a vector container in C++) which contains the actions that the user performs in the editor such as to add an object or to remove an object. Each entry in the action list contains an action ID and other information such as the object that was affected, the type of object, its position and so on. This information is very important as it's needed when we want to redo an action.

Every time we undo or redo an action we keep track of the current action that can be undone or redone by using an index value. Whenever we add an action to the list the index value is set to point to the action that was just added. When the user does a redo the index value is increased by one and for undo the index value is decreased by one. Thus the index value points to the current action that can be undone and redone (the redo action is the action above the undo action if available).

So at the start our list is empty and the index value is -1 (since there are not yet any actions); we know we cannot undo or redo as the list has no entries. We then add an object and that action is added to the actions list and the index value becomes 0:

(index=0) action=Add_obj

At this point we know we can undo adding an object but we cannot redo the action because there is no entry after the current one.

We then undo adding the object which results in the index being decreased by 1, resulting in -1. The index is effectively pointing to the position before the first action:

index=-1

(index=0) action=Add_obj

As the index is now -1 we can redo the add object operation as there is an action above the one pointed to by the index value (although the index is not actually pointing to an action).

After the redo is done the index is increased by one to 0 and we end up where we was before-we can undo the add object action once more.

To actually do an undo we do the opposite action of the one currently pointed to. For e.g., say we added an object of type 2 at position (5, 6, 8) and we get the new index of the object which is 16. Then, when we undo that action we delete the object with index of 16. If we then redo we create the object again, which is type 2 and is at position (5, 6, 8).

Another way we could do it is to not actually delete objects but instead mark them as hidden. When we undo adding an object we set the object as hidden (not in use) and then when we redo the add object action we un-hide the object. This avoids the need to store lots of object values (position rotation, etc.) in the list of actions. We can delete the hidden objects once the level is re-loaded, freeing up memory. Of course it's a good idea to limit how many times you can undo/redo to save memory. Remember if you were to impose such a limit it isn't a simple matter of just counting how many actions have been done. You will need to remove old actions when you reach a certain limit so that you can only undo/redo the most recent actions.

You may have some actions that cannot be undone (either through choice or because of a technical issue) so you may want to warn the user if they try to do such an action. Also, after saving or loading you will probably want to clear the undo/redo list.

When you do an undo/redo it is most likely that you will want a menu to update not only to tell the user what they can undo/redo but also for any undone/redone actions that affect a menu. A handy way to make sure the menu is always current if by making use of the menu's paint event which gets called whenever the menu needs redrawing. During this event get the state values and update the menu items to show the current menu text, checked value, etc.

Preventing and handling errors

As a programmer we must do our best to try to prevent problems and should an error occur we need to be able to handle error as gracefully as possible, preferably without causing the program to crash. There are minor errors which the user may never know about in which the program continues to run and then there are more serious problems in which the user will be alerted about.

Function input parameters must be checked carefully and their type must be chosen with much thought. For e.g., if a function input parameter is of type int this means we can pass both positive and negative values. If we only wanted positive values then we could either make the input parameter an unsigned int or within the function we could check the value is positive. Another thing to consider is that if only a few values can be accepted by a function then why not make the input parameter an enum?

We can only check for a number of errors but some may slip by us such as when errors happen in functions we call but didn't write ourselves. It's very important to get the return type of functions we call and for our own functions to return a value to indicate the success of the function. At the most simplest level we can return a bool; false means there was a problem, true means there was no error. If there was an error we could return the error type or log the error (such as by using OutputDebugString()).

For software that you release for others to use it's a good idea to log errors to a file with the date and time or display the information to the user via a message box. Remember that not all errors need to be logged or displayed, typically only major ones that could affect the running of the program; for minor errors they can be handled silently.

Try to avoid magic numbers as much as possible; there are values which are seemingly random and have no clear meaning. If you at least comment what the number does then that helps but what if you change the value and forget to update the comment? It is better if possible to use a const or enum. For e.g.:

const int colour=5;

const int size=6;

draw(colour, size);

Can you see that rather than pass 5 and 6 to the draw function we pass the meaningful identifiers colour and size. If the values of colour and size are later changed all parts of the program that use the identifiers colour and size will use the new values.

Programming the Kinect

Please go to Programming the Kinect.

Program your own video games

Please go to Program your own video games.

Introduction to assembly language programming

Please go to Introduction to assembly language programming

All content of this and related pages is copyright (c) James S. 2009-2018