19 Aug

Out of Memory?

It’s a common practice not to check what malloc() or new returns, since in an ideal world you will never run out of memory and so allocating memory will never fail. With a reasonably sized page file that is mostly true. When using a page file, this wouldn’t be a problem since if there is free space on the drive the page file is located, virtual memory space can be temporarily enlarged (and a message pops up mentioning that) and the application that tried to allocate memory got what it asked.

However, since I upgraded to the maximum amount of memory Windows XP supports, and switched memory paging completely off, I’ve noticed some programs will silently fail when the system runs out of memory. And this isn’t that uncommon since I develop software and the crap programmer I am, silly mistakes are and always will be made that cause huge memory usage (and there’s also the rest of the software running on the computer). I have noticed at least Firefox simply disappears, while some software die with an error message.

For a game this wouldn’t be an issue (or a web browser even) but there are tons of programs downloading stuff or just hanging there that you’ll never notice missing. But it’s annoying to notice everything isn’t as you left it.

So, in case you haven’t thought of allocation failing, you probably should do something about it. When there’s no free memory left, even a malloc(sizeof(char)) will invariably fail. A lazy way out would be wrapping the allocation with something that checks if the allocation succeeded and if not, displaying a message box will halt the program until the user does something (kills the offending app reserving all that memory or frees some disk space for the page file) and then clicks “Retry” and then the wrapper simply tries to allocate again. In C++, the new operator can be overloaded.

Just my 2 cents (Euro).

Example code

C

void * my_alloc(size_t bytes)
{
  if (NULL == (ptr = malloc(bytes)))
  {
    // malloc failed, do something about it!
  }
  return ptr;
}

C++

This uses the function from above C code.

void * operator new(size_t bytes)
{
  return my_malloc(bytes);
}
Reblog this post [with Zemanta]
21 Mar

A Tiny XML Parser

While looking for a convenient way for storing some level data for a game I’m working on (more of that later), I came across this small C++ XML parser. Originally, I wanted to stay away from XML or other formats as they are overkill for the simple game format. However, this parser is both small (the Xerces parser is over 50 megabytes!) and easy to use.

In case you can’t find a download link on the project page: you have to email the author to receive the library (the page promises a direct download link in a few weeks). I think that’s actually quite nice, considering people who write free software rarely get the praise and attention they deserve.

09 Mar

Pointers? Pointers.

This is my attempt at demystifying pointers, a very useful concept available in C, C++ and other programming languages that do not lack balls. Java and PHP have references, a similar feature (C++ also has this) but pointers pretty much are the same thing and for some reason pointers seem ancient, complex or downright frightening to some (or, most).

Why I’m writing this is because I feel a lot of tutorials do not explain pointers as well as I’d like them to explain, considering they are useful and not some archaic curiosity from the 1970s. I originally expressed the concern over here. This tutorial, or introduction, is aimed at C and C++ people because Java doesn’t have pointers and because other languages are generally for wussies.

Note: This is a living tutorial, i.e. you can suggest things and I’ll make it better. I’m all for a good pointer tutorial.

What are pointers?

At first, let’s think about computers. A very basic computer has memory for the data and the code. In a programming language, a variable refers to a location in the memory. The location, referred by address, is something like a page number in a book. At the very least, a programming language automatically assigns these memory locations and acts as a directory for the book, allowing you to refer to the locations by the variable name instead of the page number.

In a programming language, pointer is a variable that contains the address. Simple as that. In most cases, a pointer contains an address of another variable. The pointer can then be used to read or change the contents of the referred variable.

How do I use pointers?

In C, using pointers is easy. To make a variable as a pointer to another variable of type A, you define the pointer to be of type A*.

A variable=42;
A* pointer_to_a_variable=&variable;
*pointer_to_a_variable=0;

& can be read as “address of”. * can be read as “contents of”. Try reading the above example like that and you should figure out what it does.

Here is the answer:

A variable=42;
A* pointer_to_a_variable=&variable; // a pointer to the above variable
*pointer_to_a_variable=0; // the contents of the variable referred are zeroed

When should I use pointers?

A pointer can be very useful in a variety of situations. The simplest use would be something like passing a reference to a variable as a function parameter and the function then changes the variable. This is impossible without either references or pointers. At the very far end of the same spectrum, pointers are the only way to implement polymorphism in C++, which is an important and useful concept in object oriented programming.

Using pointers is natural when in a function you need to use the contents of an object given as a parameter and change them. If you don’t pass a pointer or a reference to the object, you will only change the data in the copied object. For example, see the C++ function below.

void func(Object obj) {
  obj.data=0;
}

This bit of code would be quite useless, considering the object obj is discarded after the function exits. The data member of the object passed as a parameter will not be modified because the object is duplicated for use in the function. The below function does the same but with the exact same object that was passed as a parameter.

void func(Object& obj) {
  obj.data=0;
}

Now the object is not duplicated but obj is a direct reference to the original object. data will be zeroed. Below is yet another version of the same functionality, this time with a pointer.

void func(Object* obj) {
  obj->data=0;
}

This does the same thing, only that obj is a pointer to the object. The above examples show how pointers indeed can be avoided by using references or other more modern concepts (and in some languages you are forced do it with references).

However, in C++, the above example (the one with the pointer) would also allow you to pass an object as a parameter that was inherited from the class Object. By using C++ references this is not possible. Now, if the function called a member function, it would call different bits of code depending on the object! This can be a very, very powerful and nice feature. And you can’t do it without pointers (in C++).

Show me more examples.

In C and C++, the line between arrays and pointers is a bit blurred. For example, you can use a pointer as an array, in that you can use an index with an array and a pointer. Below is an example:

int a[2]={123,456};
int* b=a;
a[0]=0;
b[1]=0;

The array a is now full of zeros. Note that b only refers to the array, it doesn’t have its own data. Also note that specifying an index eliminates the asterisk in front of b. This is because in effect b[1] is the same as *(b+1).

Continuing from the above:

int a[2]={123,456};
int* b=a;
a[0]=0;
b=b+1;
*b=0;

This also zeros the array, because the pointer b is incremented. A pointer is simply a variable with an address and you of course can change that value. This is called pointer arithmetic. It can be very helpful and actually will often allow faster code: using an index needs a multiplication while smartly incrementing pointers only needs an addition (your mileage may vary — compilers are getting better and better). See the below example:

int a[100];
int i;
for (i=0;i<100;i++) a[i]=0;

The below modification should be marginally faster.

int a[100];
int *ptr=a;
int i;
for (i=0;i<100;i++) { *ptr=0; ++ptr; }

This is because in effect, the below example only increments the pointer while the above calculates the address using index.

Note: Many younger coders suffer of premature optimization. This is not a permanent condition and will reduce with some experience. The above is not a good place to optimize (what computer can’t do that fast enough for 100 times?) but do keep that trick in mind. At the very least, it can make code a bit shorter.

Afterword

This is it for now, I can’t think of anything more about basic pointer use. Honestly, it is a bit hard to imagine things from the perspective of an absolute beginner. Any ideas are welcome.

07 Nov

What exactly does GCC optimize?

All compilers optimize code to some extent, some better than others. However, at least to me a great amount of the nature of the optimizations is unclear, outside the explicitly stated loop unrolling and like. Let’s find out which kind of programmer laziness and/or stupidity gets eliminated.

Setup

I used GCC 4.2.2 (MinGW) to compile the test program. The following options produce an assembly source of the compiled binary juxtaposed to the C source:

gcc -c -Wa,-a,-ad opt.c > opt.lst

The tests mostly check if the compiler realizes a function always returns a certain value (opt1(), opt2()), if a function call can be completely eliminated by looking at the input parameter (opt5()) and so on. While compilers do a good job at saving CPU cycles by using registers to pass parameters instead of the stack and so on, the question here is how they manage with lazy code and if you can trust the compiler to take care of some obvious optimizations and shortcuts.

Tests

Each of the following test case is called by the following line (to ensure the optimizer doesn’t just skip execution etc.):

printf("%d %d %d %d %d %d\n",opt1(),opt2(),opt3(),opt4(),opt5(0),opt5(1));

opt1()
int opt1() {
	return 6+7;	
}

The following of course always returns 13. We assume the compiler should always substitute function calls with the result.

opt2()
int opt2() {
	int x=rand();
	int y=rand();
	return x*y-x*y;   // 1-1=0
}

Always returns a zero. The function call can’t be eliminated because even if we know the result, two calls to rand() are needed. The two substitutions and multiplications can still be omitted.

opt3()
int opt3() {
	int x=rand();
	int y=rand();
	return ((x*y)<10000)?(x):(x*y);	
}

Will the compiler see it doesn’t have to calculate x*y twice?

opt4()
int opt4() {
	if (opt3()) {
		rand();	
	} else {
		rand();	
	}
	
	if (opt2()) {
                // should never get here!
		return opt3(); 
	} else {
		return 5+opt3();	
	}
}

Tests if the compiler leaves out blocks that will never be on the code path (opt2() always returns zero) and if the else-clause yields to same code as the if-clause.

opt5()
int opt5(int x) {
	return x*opt1();	
}

Does the compiler substitute the function call with the result? If x equals to zero, the result will always be zero.

Results

GCC 4.2.2 -O2 GCC 4.2.2 -O3
opt1() Call Result substituted, no call
opt2() Call, no calc, returns zero Result substituted, no call
opt3() Call, remembers x*y Inlined
opt4() Call, forgets opt2() always returns zero, although

if (opt3()) {
  rand();
} else {
  rand();
}

correctly becomes

opt3();
rand();
Inlined, all excess code eliminated
opt5() Call, calls opt1(). No optimizations Inlined, substituted

Analysis

As you can see from the results, -O2 isn’t too smart. Many clear cases such as the one with opt1() go unnoticed. I would assume a typical method that returns the value of a private member also has to be called instead of just accessed directly, so beware (note: I didn’t test g++ but as you know, it simply produces wrapper code for GCC).

-O3 on the other hand is a much better companion to a lazy coder, you can trust it eliminates downright crap code you don’t feel like cleaning manually. With -O3 you pretty much can use inlined functions instead of macros with no penalty (as long as you set the inline limits et cetera).