Part 11. What's in a name?


You will have noticed by now that there are definite names given to a variable type (such as int, double etc.). While there is nothing wrong with this, on occasion, it would be better if a double could be called something other than a double or a char something other than a char. This is where typedef steps in.

typedef name newname;

for instance

typedef char tapes;
typedef struct { (something) } name;

this has the upshot that you can give your variables a symbolic meaning (which are usually simpler to remember!)

typedef statements can also be used to define other typedefs. For instance

typedef int size;
typedef size weight;
typedef weight happiness;

happiness sad;

sad will be an int.


Enumeration (or enum) uses a defined set of integer constants.

Format :

enum tag {list} listname;

where either tag or listname can be omitted.

If we had the line

enum car_types {citroen,renault,fiat} cars;

then the constants citroen, renault and fiat are created, the tag name is car_types with one variable called cars.

Normally, the compiler will start at the left hand side and assign this a value of zero, then move one name to the right and give this one and so on until the end of the list is found. However, this can be bypassed :

enum car_types {citroen=2,renault=5,fiat=65} cars;

A nice thing about enum is that once defined, you can use the tag name to declare other enumeration variables within the program. e.g.

enum acorn {rpc=700,a=3000,master=128};

int main(void)
 enum acorn computers;
 return 0;

If a program such as this were to be run, then the output for computers would be 3000.

Black Thursday was the day when Acorn closed down their desktop division

In the example above, computers has been declared as a variable type belonging to acorn. (sorry for these references, this tutorial was written exactly a year on from Black Thursday, and I'm still a tad annoyed!!!)

Enumerations provide self documenting code (the code means something) and clarifies the structure of the program.

typedef enum {verify ,
             } discop_reasoncodes;

typedef enum {copy_files=26,
             } FSControlOps;

These two examples further illustrate that using enum will increase the readability of the main code and so make debugging far simpler (these two are both from part of the filer).

Operation bitwise....

Operator Bitwise meaning
& and
| or
^ XOR (eXclusive OR)
~ 1's compliment

There are 4 operators which work on a bit by bit level.

These will only work with int and char variables (if you remember, a bit can either be a one or a zero). Therefore, floating point numbers won't work.

What follows is known as a truth table. This shows how each of the operators work.

One's complement (~)
value result
1 0
0 1
(in otherwords, it's the opposite!)
AND (&)
value 1 value 2 result
0 0 0
0 1 0
1 0 0
1 1 1
OR (|)
value 1 value 2 result
0 0 0
0 1 1
1 0 1
1 1 1
XOR (^)
value 1 value 2 result
0 0 0
0 1 1
1 0 1
1 1 0

Try this simple & sum

1010 0110
0011 1011 &

you should get 0010 0010.

XOR has one odd thing about it. If you start with a number, XOR it by another number, the XOR it again with this same number, you end up with the original number.

The use of these bitwise operators can be used in the production of some forms of file encryption (or text encryption).

Possibly the simplest form of data encryption is using the 1's compliment (~) operator. While the output will look gibberish, it is simple to decode.

A far more secure method of encryption is the use of a seeded XOR. Here the seed is provided by either a number (inputted) or by a key press. Failure to give the correct key press (or code number) will result in the file either being spat out or XORd again (encrypting it further). The whole file is encrypted by XORing it byte by byte with the seed value. Decryption is performed with the correct seed and the XOR process repeated.

By using a combination of ^ and ~, it should be possible to create a very secure file (especially if they have seeds [except for ~]). Imagine having to crack a code which has 3 numbers (or characters) and getting it wrong further encrypts the code. The addition of a few more bitwise operators (with seeds) would further make the decryption terrible!

A small aside here.

Back in the 1980's, there was a popular home micro called the ZX Spectrum (okay, most of us will remember this machine, but this scene setting is only for the younger readers!). Like most home micro's, the Speccy had a problem with copying the software. As it was a tape based system, copying was as simple as placing the original and a blank into a double tape deck. No protection would stop this.

Some companies came up with a very cunning plan. The use of colour key code sheets to test after the program had loaded. These would invariably be unphotocopy-able and would normally be lost before the a few weeks would expire. To start off with, these cards would be (say) 4 colours by 4 blocks by 40 numbers (a total of 640 combinations). These could be hand copied in an hour or so. The protection was useless.

To get around this, companies would use 4 colours by 4 blocks by 200 numbers (3200 combinations). This would not be easy to copy, so the protection was good (until the advent of the MultiFace that is!)

The method of checking was simple and can be thought of like this

enum colours {red=1,green=2,blue=3,yellow=4};

Each block would need a checksum. Therefore if the block was red, blue, yellow, red the checksum would be 9. There would be another 3 blocks with another three checksums. This would give a total checksum for the line.

There would now be three lines of protection.

  1. Is the checksum for each block okay?
  2. Are colours in the correct order?
  3. Is the overall checksum correct?

Failure at any point and you'd need another go. Fail that and you need to reload the game.

(By opposite block I mean this :

there are 4 blocks of 4 colours per line. The opposites are

	1 -> 4	3->2
	2 -> 3	4->1

this code was finally fully hacked by a group 8 months after starting. The group were professional programmers)

To make things even tougher for the hacker (and pirate alike) would be that each block checksum would be either XORd with the checksum of the opposite block x lines down (this was defined by a code passed to it and would vary) or would have an OR or AND performed on it using the checksum from the opposite block. This meant that even if you managed to hack through to the key card codes, they would still be meaningless.

Given this choice of hours of toil or spending a tenner on a copy of the game, most spent the tenner!

Shift it

The final part of this tutorial are the shift operators, << and >>.

These shift a bit x places to the left or x place to the right.

You have to watch it when using these though. If you shift to the left, the bits move to the left, but then zeros are brought in on the right. A right shift does the same, except the zeros are brought in from the left. The exception is if the number is negative, in which case, ones are brought in. Alright, the shift is supposed to do this, but if you're not used to using shift operators, the result may not have been what is expected.

A simpler way to think about the shifts is this. A right shift is equivalent to dividing by 2, while a left shift is the equivalent of multiplying by 2. For example

i = i<<2;

will multiply i by 4.

This can be handy. The following will display a binary representation of a character (denoted by ch)

for (i=128;i>0;i=i/2)
 if (i & ch) printf("1 ");
 printf("0 ");

By using the right operator, the loop can be re-written

for (i=128; i>0 ; i=i>>1)

Time to put this to some use...

This times task is not that bad (he says).

Take the simple telephone number program and encrypt the outgoing file using as many bitwise operations and seeds as you want. The more the merrier.

On reloading though, the file must be decrypted automatically (this is the hint on how you must do this encryption).

Next time, I will look at the preprocessor.