# Computer Programming Tutorial - Advanced C-Like

## Solving All The Puzzles

You're an intermediate level programmer. If that's not true, read this introductory article or this intermediate one before continuing.

Now you're an intermediate level programmer, and you want to improve your skill to expert level. This article will help point the way. Earlier articles in this series covered the skills required for most programming, leaving out data structures, algorithms, and a few rare variable types. An expert programmer is aware of all these things, even if they go unused almost all the time.

Let's get started.

## All The Variables

• boolean - A boolean value can be true or false. In traditional C, boolean values are represented by ints but some variants (including C as of C99) have a dedicated type called "bool" or "boolean".
• char - In the previous article, I introduced char as a way to store strings. They're also a type of int, just half the size of a short.
• long long - A long long, or "long long integer" is just like an int but bigger. That means it can store a wider range of values, takes up more memory in RAM or in a file, and probably takes more time to process. Adding two long longs might take longer than adding two ints, but how much longer depends on your hardware.
• long double - A long double is just like a double, but bigger.

In the last article, I mentioned epsilon and how most of the time you don't have to worry about it. When you start tackling problems that require long doubles, you're probably worrying about epsilon and rounding errors.

It's a complicated problem, and this is an advanced article, but see this reference for a good explanation. In short, floating point numbers have a limited number of digits so when they get large enough adding one is the same as adding zero.

Type NameSize In BytesRange

boolean

4

true/false

char

1

+/- 127 (2^7 - 1)

long long

8

+/- 2^63 -1

long double

10 to 16

+/- 1.18e4932

## More Integers With Enumerated Types

An enum or "enumerated type" allows you to define a set of int constants that make your program easier to read. The first constant in the list is 0, the next is 1, and so on.

Don't forget that they're ints. In the boolean example to the right, false is 0 and true is 1 so "if (false)" and "if (true)" work as expected, but "if (true == (expression))" is not the same as "if (expression)" because in C any non-zero integer value is true even though you've defined an enum called boolean where true is always 1.

## Modifying Variables With Const Extern Static

Const, extern, and static can be used to modify a variable in different ways.

A variable declared as const is a constant, meaning its value can never change.

A variable declared as extern is shared between source files.

A variable declared as static inside a function will maintain its value between function calls. It's like a global variable that can only be accessed from within that function.

## Pushing the Limits

What if you want to go beyond the limits? Maybe your program needs very large ints or very precise floats. You can make a new type of data with struct. College programming courses often give such an assignment in the first year or two: write a set of functions and data structures to support operations on very large integers (hundreds of digits).

To accomplish this, a student might define a struct BigIntegerStruct and make it a new type BigIntegerType with typedef. In practice, BigIntegerStruct and BigIntegerType need not be different names and you could call them both BigInteger: typedef struct BigInteger {...} BigInteger;

Defining the usual integer operations on this new type allows a programmer to break the larger puzzle into smaller parts that are each more easily solved and tested than the whole. A the same time, students are introduced to the idea of an algorithm (a series of steps that eventually solves a puzzle) and how to analyze the order of its runtime in terms of its inputs. In the case of big integers, adding and subtracting take as much time as the length of their inputs, or O(n). Multiplying and dividing would take as much time as the product of the length of their inputs, or O(n2).

0

0x0

1..8

0x1..0x8

9

0x9

10

0xA

11

0xB

12

0xC

13

0xD

14

0xE

15

0xF

inputinputoutput

0

0

0

0

1

1

1

0

1

1

1

0

## Integer Operations

Until now, you were probably aware that C data types are each a series of one or more bytes, and that bytes are each eight bits, and that each bit is 0 or 1. C allows you to manipulate and test these bits directly. To help with this, you can define integer values with a leading 0x to specify a hexadecimal value, and use %x or %X in the printf() format string to display an int in base 16.

The usual operators still apply: + - * / % and recall the tests == > < >= <=. Testing an integer by itself is false if the integer is 0, and true otherwise.

Add to these operators: & (AND), | (OR), ^(XOR), and the unary ~(NOT) which turns all 1s to 0s, and 0s to 1s. The bitwise AND and OR work just like their logical counterparts, but treat each integer as an array of boolean. XOR (exclusive OR) is true only if exactly one of its two inputs is true. That is 1^0 and 0^1 are both true (1), and 1^1 and 0^0 are both false (0).

You can also shift bits right (>>) and left (<<) within an integer. The picture at the top of this article shows a right shift in action.

With these operations, you can treat an int (x) as an array of 32 bits and test bit n (0-31) with:

• if (x & (1<<n))

Why would you want to do this? Most of the time, you wouldn't want to. For example you may have wondered why a C99 standard boolean value takes up as much as an int (four bytes, or 32 bits) when boolean data is only one bit's worth. The reason is speed. Until you run out of RAM, speed is more important than memory and checking the value of an int is usually faster than isolating one bit and then checking its value.

But not always. If your program needs enough boolean values and needs to access them at random, eventually the bottleneck is moving data instead of processing data. Even in cases where it's better to use one bit per boolean, it's almost always not important and it's simpler to just use an int.

This point about simplicity bears emphasis. Simplicity wins. When you achieve an expert level of knowledge, don't spend it as fast as you can. Do it the boring way. Do it the boring way until an expert level of knowledge is required because none of the boring options are good enough.

## Future Directions

In these three articles I have attempted to treat C-Like languages as more alike than they are different, but actual programming is done in an actual language with all of its strengths and weaknesses bundled in.

To gain further skill, a programmer must appreciate language differences despite all similarities. C is still the Latin of modern computing, but the Renaissance is in full swing and important scholars are studying in French, Italian, Spanish, English, German, each with its own purpose whether those purposes are achieved or not.

For your next mission should you choose to accept it, focus on one language at a time (like C). It may be the language you have to use for a particular project, or one that has idioms you wish to emulate, or simply one that interests you for interest's own sake.

Whatever path you choose from here, you're already well on your way to spending the roughly 10,000 hours of practice that it takes to be a world class expert.