Friday, August 1, 2008

Answer to C - Pitfalls part II





Porting/portability issues regarding C/C++

Allright. one of the big things in the programming today is portability. Windows is still the most common operating system in PCs, but finally one can see some ineterst in big companies to also build some linux support in their applications. Mac is still alive too, and it is far cheaper to write software so, that you can use at least some common parts of it for all platforms. Another portability issue is different hardware architectures. 64 bit systems are increasing, and soon they will propably be more popular than traditional 32 bit architectures.

So how does one create portable code? What things to consider?

It all begins from planning. First of all you need to carefullly estimate what kind of general requirements there will be for your program, supprted platforms amongst others. After these are somehow clear, you need to decide which language you will use for your program.

Let's assume you ended up needing support for many platforms, and both 32 and 64 bit architectures. Lets further assume, that for some odd reason, you deducted that best language to use is C. After you have reshecked your calculations, and still failed to find the error which led you to using C, you need to decide what should you do all by yourself, and where you should/can use 3.rd party libraries...

So first step is to choose portable libraries. Fortunately there's many good libraries which can be used on multiple platforms, via similar interface. There's openGL & co. for graphics, there's pthreads for windows and unix threads, there's PoSIX sockets and winsock (which have some differencies in basic usage, but those can be quite easily hidden)... Plenty of good stuff.

And what do you need to take in consideration while writing actual implementation? First you need to decide what compilers to use for which platforms. In linux world I can only see one reasonable possibility - gcc. But on windows... Well, this is a bit thougher. There is mingw version of gcc for windows, but I am really not that familiar with it, nor am I sure about the libraries available for it. There's also M$ Visual XXXXX family of compilers, and I've heard some of them are quite ok. But with M$ products you will propably get the world's most standards breaking product... And naturally that's bad for portability.

What ever do you decide, you must be carefull with the functions you use. ANSI C functions should all be quite similar on both M$ compiler and GCC, but the excellent features of PoSIX standard interface offers are often quite cribbled on M$ side. As a good example, I need to ask what was wrong with snprintf()? Honestly? Why did M$ have to do _snprintf? Just to be a pain??

And naturally there's those fundamental differences in the princibles of operating systems. For example in mapping the virtual memory for processes. Linux kernel may hide same physical addresses behind different virtual addresses in each process. Eg. Your perfectly valid pointer in one process pointing at your cleverly built data storage will be pointing at invalid location in other process. Thus making it meaningless to pass raw address data from one process to other. Also shared memory, signals, scheduling... all of these are different. And your application needs to tackle each of these problems. Hopeless mess? No, there is projects which have succeeded in quest of portability. Errorprone? Sure as hell. You need to plan things c*a*r*e*f*u*l*l*y beforehand. Hard but doable.

Now in the pitfall II I said I'll show you one portability problem. But it was not problem related to porting software from one system to other, instead it was a problem related to making software to work both on 32 and 64 bit systems. Remember following:

In 64 bit systems, forcing pointer to transform itself into a integer leads thy to death and destruction. Well, at least to segmentation faults.

At 64 bit systems, pointer is 64 bits wide, not 32 as it is in 32 bit systems. So when you place such a pointer in integer (by casting), you'll lose half of the address...

other issues to consider are:

Structures which contain pointers, and which are populated by believing in knowing their size / accessing members by using hardcoded offsets.
Functions which might return pointer or integer depending on situation.
hardcoded bit shifts.

And so on.

But once again the night is falling in Finland, and I'd better get my head on pillow...

No comments:

Post a Comment