How To: Represent Numbers in Dec, Hex, and Oct

Introduction

In C and C++, you can have 3 ways of write a number:

  • Using Decimal (base-10) notation
    Very nice for general numbers. It’s easy to read and maintain. Read about decimal notation here.
  • Using Hexadecimal (base-16) notation
    Very efficient for flags especially if you need to see how bits are organized. Plus, it is very popular in C and C++. Read about hexadecimal notation here.
  • Using Octal (base-8) notation
    Not very friendly for most developers and for team mates of course. Read about octal notation here.

Unfortunately, you cannot write a binary number directly in your code. Convert it to any of the three notations first. Read about binary notation here.

Decimal Representation

Just as you write number on papers, you can write it in your code.

	int i = 100;

And you can use the format specifier %d to display the number as decimal using the printf function and its €œsisters€ (e.g. wsprinf in Windows).

	printf("%d", i);

Hexadecimal Representation

Just convert the number to hex and write it prefixed with 0x.

	int i = 0x64;

And you can use the format specifier %x to display the number as hexadecimal as small letters. And %X to display it as capital letters.

	printf("0x%x", i);

Octal Representation

Convert the number to oct and write it prefixed with 0.

	int i = 0144;

Of course, you can use printf to display octal numbers. And this is done through the %o format specifier.

	printf("%o", i);

Beware while reading octal numbers. Octal representation is very similar to decimal. 0144 equals to 100 in decimal notation and 0x64 in hexadecimal.

Unfortunately, you can’t use printf to display numbers in binary notation. You can make your own routine that accomplishes that.

BOOL or BOOLEAN?

هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.

Windows comes with two types that represent a Boolean variable (TRUE or FALSE.) Both represent FALSE if 0 and TRUE if non-zero.

The big difference you need to care when working with that two Booleans is that BOOL defined as int which is 32 bits (4 bytes) on 32-bit environments and 16 bits (2 bytes) on 16-bit environments. BOOLEAN on the other hand, defined as BYTE, which in turn defined as unsigned char. Thus, BOOLEAN only occupies 8 bits (1 byte) from memory.

Although you can convert between them easily, BOOL is much common than BOOLEAN and it is very popular in the Windows API.

Now, the decision is yours!

A Short Speech about Unions

هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.

Contents

Contents of this article:

  • Contents
  • Definition
  • Unions and Structures
  • Example
  • Results
  • Unions Usefulness
  • Unions and the API

Definition

A union is a memory location that is shared by two or more different types of variables. A union provides a way for interpreting the same bit pattern in two or more different ways (or forms.)

Unions and Structures

In fact, unions share structures lots of characteristics, like the way they defined and marshaled. It might be helpful to know that, like structures, unions can be defined inside a structure or even as a single entity. In addition, unions can define complex types inside, like structures too.

Example

To understand unions, we will take a simple example. Consider the following union:

typedef union CHARACTER
{
	int i;
	char c;
};

This was a simple union defines a character. It declared two members, i and c, it defined them in the same memory location. Thus, it provides two ways for accessing the character, by its code (int) and by its value (char). For this to work it allocates enough memory storage for holding the largest member of the union and that member is called container. Other members will overlap with the container. In our case, the container is i because it is 4 bytes (on Win32, 16 on Win16), while c is only 1 byte. Figure 1 shows how the memory is allocated for the union.

Figure 1 - CHARACTER union into memory

Results

Because the two members are sharing the same memory location, when you change one member the other is changed too. Consider the following example:

int main()
{
	union CHARACTER ch;

	ch.i = 65;				// 65 for A
	printf("c = %c", ch.c);	// prints 'A'
	printf("n");

	ch.c += 32;				// 97 for a
	printf("i = %d", ch.i);	// prints '97'
	printf("n");

	return 0;
}

When you change any of the members of the union, other members change too because they are all same the same memory address.

Now consider the same example but with values that won’t fit into the char member:

int main()
{
	union CHARACTER ch;

	ch.i = 330;
	printf("c = %c", ch.c);	// prints 'J'
	printf("n");		// Ops!

	ch.c += 32;
	printf("i = %d", ch.i);	// prints '362'
	printf("n");

	return 0;
}

What’s happened? Because char is 1 bye wide, it interprets only the first 8 bits of the union that are equal to 32.

The same rule applies if you add another member to the union. See the following example. Notice that order of member declarations doesn’t matter.

int main()
{
	union {
		int i;
		char c;
		short n;
	} ch;

	ch.i = 2774186;

	printf("i = %d", ch.i);
	printf("n");
	printf("c = %i",
		(unsigned char)ch.c);
	printf("n");
	printf("n = %d", ch.n);
	printf("n");

	return 0;
}

Now, i, the container, interprets the 32 bits. c, interprets the first 8 bits (notice that we converted it to unsigned char to not to show the negative value.) n, interprets the first high word (16 bits.)

Unions Usefulness

You might ask: Why I need unions at all? I could easily use the cast operator to convert between data types!

The answer is very easy. Unions come very efficient when casting between types require much overhead. Consider the following example: You are about to write an integer to a file. Unfortunately, there’s no function in the C standard library that allow you to write an int to a file, and to using fwrite function requires excessive overhead. The perfect solution is to define a union that contains an integer and a character array to allow it to be interpreted as an integer and as a character array when you need to pass it to fwrite for example. See the following code snippet:

union myval{
	int i;
	char str[4];
};

In addition, unions offer you more performance than casts. Moreover, your code will be more readable and efficient when you use unions.

Unions and the API

Unions exist throughout the API, however, they are usually declared inside structures and not as a single unit. A good example is the DEVMODE structure.

Why is it preferred using unions inside structures? It doesn’t make much sense if they were a single unit. For our example, you could easily convert the integer to a character rather than creating a union. However, the efficiency of unions comes when they are declared inside structures. In addition, you gain more performance (and scalability of course) when you work with unions.