PDA

View Full Version : C/C++ integer types


Paul C. Anagnostopoulos
16th July 2005, 06:46 AM
So I find myself programming in C/C++ for the first time in about six years. Yikes, what a whacky language this is. Anyhoo ...

What is the best way to set up typedefs for integers? My preference is that declaring an "integer" should automatically give me 32-bit integers on 32-bit systems and 64-bit integers on 64-bit systems. I would settle for "integer" always giving one or the other based on some conditional shenanigans in the header file.

Meanwhile, I can define int16, int32, and int64 to give me specific widths when I want them.

Do I simply use int to get the result I want?

~~ Paul

roger
16th July 2005, 07:24 AM
Paul,

If you truly want to be flexible, I think you should probably stay away from just using int. Instead, I would make up a typedef for the machine int. For example:

<code>
#ifdef WINBOX_32BITPROCESSOR
typedef int MACHINEINT;

#elsif WINBOX_64BITPROCESSOR
typedef int MACHINEINT;

#elsif WEIRDBOX_32BITPROCESSOR
typedef long MACHINEINT;

#elsif OLD16BITCOMPILER_32BITPROCESSOR
typedef long MACHINEINT;

#elsif UNCOMPLIANT_COMPILER_32BITPROCESSOR
typedef noint NOTSUPPORTED; // this will not compile on purpose

#endif

</code>


The idea is that any specific combination of compiler and processor may give you a different length for int. An old 16 bit compiler may use 16 bit ints on a new 64-bit processor. Replace the conditions in the ifdef with realistic ones that work for the processors you use, and you'll probably want to include an #else that causes a compile error so you catch when you are compiling on a platform/compiler combination that you haven't yet coded for.

Stimpson J. Cat
16th July 2005, 02:53 PM
Well, the size_t and ptrdiff_t types are supposed to be unsigned and signed integers with the same size as pointers on that platform, so you could probably just use them.

Dr. Stupid

Paul C. Anagnostopoulos
16th July 2005, 03:33 PM
That's the ticket! I figured there had to be something that told me the native integer size of the machine.

Say, what's the best online C/C++ reference manual?

~~ Paul

Paul C. Anagnostopoulos
16th July 2005, 03:36 PM
You know there is something wrong with a language when there are so many names beginning with double underscore.

~~ Paul

Stimpson J. Cat
16th July 2005, 04:14 PM
That's the ticket! I figured there had to be something that told me the native integer size of the machine.
I guess technically it tells you the native pointer size, but I would imagine that they are usually the same thing. Things get a bit tricky when dealing with files, though. Using 64 bit file pointers on 32 bit systems is a royal pain in the ass.

Say, what's the best online C/C++ reference manual?

I guess it depends on what you are looking for.

For STL stuff I usually refer to here.

http://www.sgi.com/tech/stl/index.html

For general stuff about the language, this site is pretty good.

http://www.icce.rug.nl/documents/cplusplus/

You know there is something wrong with a language when there are so many names beginning with double underscore.
But you're not actually supposed to use that stuff. Not if you want your code to be standards compliant, anyway. ;)


Dr. Stupid

epepke
17th July 2005, 02:53 AM
Originally posted by Stimpson J. Cat
I guess technically it tells you the native pointer size, but I would imagine that they are usually the same thing.

Not always. On the Palm under 68K, an int is 16 bits while a pointer is 32 bits, but under ARM, an int is 32 bits.

I'm not sure I understand Paul's problem, though, except to gripe about C and C++. When I write code for multiple platforms, and most of the time when I write code for single platforms, I never use int at all except occasionally for small counters, and I typedef everything, so even the elementary types such as short, long, and char only appear in header files. This seems like a pain to set up in the first place, but it saves a lot of headaches later on.

Trouble is that it doesn't work for enums, because the size of an enum is usually a compiler option..

Stimpson J. Cat
17th July 2005, 06:48 AM
epepke,

I guess technically it tells you the native pointer size, but I would imagine that they are usually the same thing.
Not always. On the Palm under 68K, an int is 16 bits while a pointer is 32 bits, but under ARM, an int is 32 bits.
I'm not talking about the size of the C/C++ int type. I am talking about the native word size of the CPU's integer computation. I do not know of any CPUs for which the native word size and pointer size are different, although there certainly may be some.

I'm not sure I understand Paul's problem, though, except to gripe about C and C++.
When he posted the question I assumed that his problem was that he needed an integer type that could portably store values such as array sizes and differences between addresses. This is precisely what the size_t and ptrdiff_t typedefs are for.

It sounds to me now like he wants to use the integer type which, on whichever platform is being used, will be most natural for that platform. This is a legitimate concern for some applications. For example, if your CPU is designed to perform integer operations at 32 bit, then operating on larger integers (say 64 bits) will usually be slower. Likewise operating on smaller integers will typically involved promoting them to 32 bits first, incurring unnecessary overhead. If your not concerned with operating on very large integers, and just want to make sure your integer math is done in the most optimal way possible, then having a typedef to the platform's native integer type makes a lot of sense. Again, I think that on most, if not all, platforms, size_t and ptrdiff_t will accomplish this.

When I write code for multiple platforms, and most of the time when I write code for single platforms, I never use int at all except occasionally for small counters, and I typedef everything, so even the elementary types such as short, long, and char only appear in header files. This seems like a pain to set up in the first place, but it saves a lot of headaches later on.
Same here, although I have yet to find a case where one of the typedefs provided by the standard library doesn't already serve my purposes.

Trouble is that it doesn't work for enums, because the size of an enum is usually a compiler option..
Yeah, but usually the size of an enum isn't very important.


Dr. Stupid

Paul C. Anagnostopoulos
17th July 2005, 07:41 AM
Epepke said:
I'm not sure I understand Paul's problem, though, except to gripe about C and C++. When I write code for multiple platforms, and most of the time when I write code for single platforms, I never use int at all except occasionally for small counters, and I typedef everything, so even the elementary types such as short, long, and char only appear in header files. This seems like a pain to set up in the first place, but it saves a lot of headaches later on.
Well, I do enjoy griping about programming languages, I must admit. I've done it for about 35 years, so I'm not stopping now.

I agree with your philosophy: Always use typedefs established in header files. Now, how do I do this:

typedef ?int? integer

so that the integer type is the native size of mathematical integers on the machine? I don't care about pointers or vector lengths. I just want integer arithmetic to be performed natively.

A separate question is how to get native pointers, but that would happen with this, right?

typedef char* pointer



Stimpy said:
It sounds to me now like he wants to use the integer type which, on whichever platform is being used, will be most natural for that platform. This is a legitimate concern for some applications. For example, if your CPU is designed to perform integer operations at 32 bit, then operating on larger integers (say 64 bits) will usually be slower. Likewise operating on smaller integers will typically involved promoting them to 32 bits first, incurring unnecessary overhead. If your not concerned with operating on very large integers, and just want to make sure your integer math is done in the most optimal way possible, then having a typedef to the platform's native integer type makes a lot of sense. Again, I think that on most, if not all, platforms, size_t and ptrdiff_t will accomplish this.
You've got it. Sounds like ptrdiff_t might do the trick. size_t is unsigned.

~~ Paul

69dodge
17th July 2005, 09:38 AM
I think you just want int.

The C++ standard says (3.9.1):<blockquote>There are four signed integer types: "signed char", "short int", "int", and "long int." In this list, each type provides at least as much storage as those preceding it in the list. Plain ints have the natural size suggested by the architecture of the execution environment; the other signed integer types are provided to meet special needs.</blockquote>As far as pointers go, why use a typedef? It's not like the syntax for declaring pointers in C is going to change. If you want to declare a variable named p to be of type "pointer to T", just say<blockquote>T *p;</blockquote>What are you planning to do with your pointers? To manipulate memory at a low level, byte by byte, a pointer to char is appropriate. But a variable that will point to objects of a specific type should be declared as a pointer to that type. If you want a "generic" pointer, which you won't ever actually dereference, the idiom is a pointer to void.

roger
17th July 2005, 10:53 AM
Is my post invisible? :D

My header file gives you what you need, Paul. Not all compilers are compliant, and so not all ints will default to the native architecture. Take an old 16 bit compiler, and you are going to get 16 bit ints.

Just make your own int typedef, and conditional compile it. That is guaranteed to work with any compiler/platform combination.

typedef int NativeInt;

will work on the vast majority of platforms that you encounter.



Realistically, a compiler is going to implement int to be efficient, so you really are safe using int if you are just looking for speed.

LW
17th July 2005, 11:59 AM
Originally posted by roger
Not all compilers are compliant, and so not all ints will default to the native architecture.

There are few reasons to use a non-compliant compiler. Actually, the only good reason to do so is that there is no compliant compiler available for your environment.

epepke
17th July 2005, 03:16 PM
Originally posted by Stimpson J. Cat
Not always. On the Palm under 68K, an int is 16 bits while a pointer is 32 bits, but under ARM, an int is 32 bits.
I'm not talking about the size of the C/C++ int type. I am talking about the native word size of the CPU's integer computation. I do not know of any CPUs for which the native word size and pointer size are different, although there certainly may be some.

I am, and that's what I pointed out. I'll try it again. On the DragonBall processors used in pre-OS5 Palm OS devices, which processors are still used in some embedded systems and are still emulated under ARM on OS5 devices, the native integer computation size is 16 bits, while the native address size is 32 bits.

There are some 32-bit arithmetic instructions, but there is, for example, no instruction to multiply a 32-bit register by another 32-bit register.

This is not simply academic. CodeWarrior 9, in which a lot of Palm stuff that I make some money on maintaining still requires, uses a subroutine (which is called something like __lmul) to multiply 32-bit quantities. However, when writing shared libraries, the library that has this function is not usually linked in. As a result, if you have to do any multidimensional array index or pointer calculations, you're up the creek without a paddle. The compiler isn't smart enough to produce code without the subroutine. In practice, it's easiest on the rare occasions when this happens to do shifts and multiple multiplications.

Yeah, but usually the size of an enum isn't very important.

It is when it's in a structure, and the structure needs to be passed between 68K and ARM processors, which happens with Palm OS5 devices. Also when one needs to pass structures between, say, CodeWarrior code and GCC code.

Again, this isn't simply academic. I have to deal with this kind of code on a nearly daily basis.

Stimpson J. Cat
17th July 2005, 04:05 PM
epepke,

I'm not talking about the size of the C/C++ int type. I am talking about the native word size of the CPU's integer computation. I do not know of any CPUs for which the native word size and pointer size are different, although there certainly may be some.
I am, and that's what I pointed out. I'll try it again. On the DragonBall processors used in pre-OS5 Palm OS devices, which processors are still used in some embedded systems and are still emulated under ARM on OS5 devices, the native integer computation size is 16 bits, while the native address size is 32 bits.
OK. So now I know of a CPU for which they are different. ;)

Yeah, but usually the size of an enum isn't very important.
It is when it's in a structure, and the structure needs to be passed between 68K and ARM processors, which happens with Palm OS5 devices. Also when one needs to pass structures between, say, CodeWarrior code and GCC code.

Again, this isn't simply academic. I have to deal with this kind of code on a nearly daily basis.
That sounds pretty strange to me. So you have to manually make sure that all types are the same size on both platforms? I would think enums would be the least of your problems. How do you deal with things like alignment restrictions, or padding in structures?

Sounds to me like a bloody nightmare.


Dr. Stupid

Paul C. Anagnostopoulos
17th July 2005, 05:48 PM
Roger said:
Is my post invisible?

My header file gives you what you need, Paul. Not all compilers are compliant, and so not all ints will default to the native architecture. Take an old 16 bit compiler, and you are going to get 16 bit ints.
I read your post, but I was hoping something like:

typedef ptrdiff_t integer

would do the trick, since it is so much simpler.

Isn't there a preprocessor constant that specifies the number of bits in the machine word?

This should not be this difficult.

~~ Paul

epepke
17th July 2005, 10:55 PM
Originally posted by Stimpson J. Cat
That sounds pretty strange to me. So you have to manually make sure that all types are the same size on both platforms? I would think enums would be the least of your problems. How do you deal with things like alignment restrictions, or padding in structures?

That's perceptive. Yes, the Dragonball and ARM also have different alignments: the ARM uses natural alignment, and the Dragonball uses word alignment. That caused problems, too. Almost all of the structures needed to be reworked, and one or two had to be accessed with offsets, as they were parts of resources.

Sounds to me like a bloody nightmare.

It was. It was also complicated by the fact that the application (a bytecode interpreter for a development package) had structures all over the place, and since the main loop had to be in ARM, I had to convert it pretty much all at once. It took a couple of months.

69dodge
18th July 2005, 12:27 AM
Originally posted by Paul C. Anagnostopoulos
Isn't there a preprocessor constant that specifies the number of bits in the machine word?How would the preprocessor of an old compiler know what new machine its generated code might be run on? Is there some machine-independent way of determining, at runtime, the machine word size?

roger
18th July 2005, 10:17 AM
Originally posted by 69dodge
How would the preprocessor of an old compiler know what new machine its generated code might be run on? Is there some machine-independent way of determining, at runtime, the machine word size? Why would you want to do it at runtime?
ETA: never mind. What a stupid question I just asked.

My point, though, is that at runtime it's too late, since the compiler decides the size of all the types.

roger
18th July 2005, 10:28 AM
Originally posted by LW
There are few reasons to use a non-compliant compiler. Actually, the only good reason to do so is that there is no compliant compiler available for your environment. Depends. A lot of our business is adding a little thingy here or there to existing code we did many years ago with an old compiler. It's cheapest for the customer, and us, to just use the old compiler and add in the relevant code, rather than recompile with a new compiler, change things, test things, etc.

But I certainly agree that it doesn't sound like Paul is, or will be, facing that case, and he is going to be fine using plain ole int.

Paul C. Anagnostopoulos
18th July 2005, 10:38 AM
69dodge said:
How would the preprocessor of an old compiler know what new machine its generated code might be run on? Is there some machine-independent way of determining, at runtime, the machine word size?
The preprocessor could know just the same way as the back end knows what machine to generate code for. If you don't know how many bits in the word of the target machine, then you probably don't know it's architecture, which means you can't generate code for it anyway.

After all, the int type specifies a certain number of bits, even if it is apparently a secret from the programmer.

~~ Paul

69dodge
18th July 2005, 11:13 AM
C has a bunch of macros, defined in the header &lt;limits.h&gt;, that tell you about the different C types, e.g., INT_MIN, INT_MAX, LONG_MIN, LONG_MAX, etc.

C++ retains those macros for backward compatibility, but the preferred way to find out that sort of information in C++ is the various specializations of a class template called numeric_limits, defined in the header &lt;limits&gt;.

So you can find out how many bits an int has, but you still don't know what processor you're running on or whether the compiler's int has the "natural" size for that processor. An old compiler that was written for, say, an Intel 8088 generates code that will probably run on a Pentium, but its ints will be smaller than optimal.

LW
18th July 2005, 11:19 AM
Originally posted by Paul C. Anagnostopoulos
After all, the int type specifies a certain number of bits, even if it is apparently a secret from the programmer.

Not a secret, it is in the compiler documentation.

In most environments you can determine the number of bits runtime with:

sizeof(int) * CHAR_BIT


(This might not work in some exotic architectures).

Paul C. Anagnostopoulos
18th July 2005, 11:35 AM
LW said:
Not a secret, it is in the compiler documentation.
Good point, although it's still a secret programatically.

In most environments you can determine the number of bits runtime with:
But that doesn't help me conjure up a compile-time type.

~~ Paul