Thursday, November 29, 2007

Handling of integer datatypes

Since the MS-DOS based Turbo C compiler is 16-bit and GNU gcc is inherently 32-bit, there are some unfortunate discrepancies in the sizes of integer datatypes between them. This usually doesn't matter, but sometimes does matter -- for example, in disk i/o or where the programmer has counted on certain types of rollover.

The TurboC library allows you to handle this problem in two separate ways, at your option. The first way, of course, is simply to ignore the problem and to assume that an int is an int is an int. :-) In other words, datatypes can be left unchanged, and it's up to you to figure it out later, if your program doesn't work. By default, though, TurboC redefines the words short, int , unsigned, and long using macros so that they are replaced by GNU datatypes specifically corresponding to the Turbo C datatypes, namely:

#define short int16_t
#define int int16_t
#define unsigned uint16_t
#define long int32_t
(You may wonder why there's a macro for long, since it's a 32-bit datatype on both Turbo C and gcc. If so, you've fallen into the Turbo-thinking trap! The long datatype is 64-bit for some CPU types supported by gcc.)

This scheme has the advantage of transparently fixing almost all data declarations in your program. Those declarations which are not fixed properly, such as unsigned long or the use of unsigned to define bitfields in a struct, are broken. This is actually good news, because the compiler gives you an error message and you're allowed to fix the problem, rather than just allowing you to assume everything is swell. The resources you have to fix the problems with are the various explicit datatypes provided by GNU gcc (int8_t,uint8_t, int16_t, uint16_t, int32_t, and uint32_t) and some new datatypes defined by the TurboC library corresponding to the original (non-macro-replaced) GNU datatypes: gchar, gschar , guchar, gshort, gushort, gint, guint, glong, and gulong.

For example, after automatic macro conversion, things like the following will be correct

int i, j, k;
unsigned u;
char c;
short is;
long n;
but things like this will be wrong:
unsigned int i, j, k; // Change to unsigned or to uint16_t.
unsigned char c; // Change to uint8_t.
struct MyStruct
{
int i; // Okay.
unsigned x:1; // change to guint.
unsigned y:2; // change to guint.
};
int main (int argc, char *argv[]) // Change to gint.
{
...
}
The automatic conversions are enabled by default, but can be disabled with the "-DDoNotFixIntegers" compiler switch. You have to decide for yourself which is more appropriate. Enabling the automatic conversions means that your program is more likely to work correctly once ported. But it also means that it may be more difficult to maintain afterward because it will be filled with things that look like int but aren't really.

Note that if you want to use "-DDoNotFixIntegers" to compile the code you're porting, a different version of the library is used -- libTurboCu.a rather than libTurboC.a. Both library versions are automatically built, for versions 20020319 or later. (For earlier versions, I'm afraid you'll have to build libTurboCu.a yourself by manually changing the Makefile to have the gcc switch -DDoNotFixIntegers).

Here is a tabular summary of how the integer datatype declarations are handled if converted automatically by the TurboC library:

Turbo C type Size Equivalent
GNU gcc type
Handling by TurboC
char 8 char Correct
signed char 8 signed char Correct
unsigned char 8 uint8_t Causes compile-time error. Replace manually with uint8_t .
short 16 int16_t Correct
unsigned short 16 uint16_t Causes compile-time error. Replace manually with uint16_t .
short int 16 int16_t Causes compile-time error. Replace manually with short .
unsigned short int 16 uint16_t Causes compile-time error. Replace manually with uint16_t .
int 16 int16_t Correct
int bitfields in structs varies int Causes a compile-time error. Replace manually with gint .
unsigned int 16 uint16_t Causes compile-time error. Replace manually with unsigned .
unsigned 16 uint16_t Correct
unsigned bitfields in structs varies unsigned Causes a compile-time error. Replace manually with guint .
long 32 int32_t Correct
unsigned long 32 uint32_t Causes compile-time error. Replace manually with uint32_t .
long int 32 int32_t Causes compile-time error. Replace manually with long .
unsigned long int 32 uint32_t Causes compile-time error. Replace manually with uint32_t .

No comments: