Portable Code: How To Check If A Machine Is 32 Bit Or 64 Bit
Subscribe To Our Feed | Follow Us On Twitter | Get Updates on Email
Writing portable code is very important but it is one of the aspects that most people neglect until it is too late to realize its importance. Till few years ago, most people writing code for personal computers were not worried about the data sizes on their machines. They didn’t even think whether the machines, on which their code would be running, would be 32 bit or 64 bit. But the recent advent of 64 bit machines in normal every-day usage has them running helter-skelter to get their programs into shape. Many of these programs would like to run the same code base on 32 bit as well as 64 bit machines. There are many ways to do it. A few allow us to use data types that would work as expected in both machines while in other ways, they explicitly check for the architecture of the machine and carry out their tasks accordingly. Before I give you the code to run this check, let’s see a bit of theory behind it.
First, let’s be clear that the discussion we will be doing now will not always give you the “hardware architecture” of a machine. Rather it’ll allow you to know the “Programming Model” (or Data Model)that the OS or your compiler enforces on you. What I mean is that if you run a 32 bit OS on top of your latest 64 bit processor based system, it will still mean a 32 bit programming model for you. Infact, if you were to compile your programs using the ancient Turbo C compiler, you’d be in for an even bigger surprise
. That said, ultimately the programming model is what you’d be interested in knowing to make sure that your program can compile and run accurately on that particular system. The most common programming models in use are as below:
| Datatype | LP64 | ILP64 | SILP64 | LLP64 | ILP32 | LP32 |
| char | 8 | 8 | 8 | 8 | 8 | 8 |
| short | 16 | 16 | 64 | 16 | 16 | 16 |
| int | 32 | 64 | 64 | 32 | 32 | 16 |
| long | 64 | 64 | 64 | 32 | 32 | 32 |
| long long | 64 | 64 | 64 | 64 | 64 | 64 |
| pointer | 64 | 64 | 64 | 64 | 32 | 32 |
So, what do we infer from this table? The glaring issues are that we can no longer depend on the sizes of data types with which we work. If your program does not make use of the data type sizes (either explicitly or implicity, e.g. by type conversion like converting between pointers and integers), most probably you will be safe by just recompiling your code for the new machine without changing it. Otherwise, a safe bet is to base your code around either all char’s or long long’s because this data type will always have the same size across machines.
Now, onto the “check”. If you read the above table carefully, you will come to know that most of the data type sizes can be misleading, i.e. they can be 32 bit even on 64 bit architectures. So, most people who make the mistake of using the size of integer on a machine for their checks fall into this trap. However, one of them that is useful for us is “The Pointer”. Yes, in all these models, the pointer to a data type is always 64 bit on 64 bit architectures and 32 bit on 32 bit architectures. Hence, the check becomes rather trivial, i.e.
n = sizeof(void *);
The above expression results in n being equal to 8 on a 64 bit architecture and 4 on a 32 bit architecture. So, there it is but remember that should not try this out with function pointers because that can lead to wrong results but that is a topic for some other time. We’ll bring you a few more articles about 32 bit vs 64 bit programming, its pitfalls, issues and areas where we can optimize and take advantage. Please let us know if you’d like us to cover a certain aspect in particular.
© Safer Code | Portable Code: How To Check If A Machine Is 32 Bit Or 64 Bit
|
Liked this post? Get FREE Updates Subscribe to RSS feed |
Related posts
Tags: 32–bit, 64–bit, Architectue, C, check machine 64 bit, CPP, Data Model, data models, data sizes, data types, function pointers, Hardware Architecture, ILP32, ILP64, LLP64, LP32, LP64, pointers, Portable code, Programming Model, SILP64, writing portable code






Nice try, but this approach will not work on processors that use word addressing, such as the Cray PVP. Many DSPs use word addressing and they get around this problem by defining the character types to be 16 or 32-bits.
Check out the ‘Common implementation’ discussion in: http://c0x.coding-guidelines.com/3.6.pdf
@Derek: yeah. I just read through the document. So, this approach might have issues on some machines which do not follow the data models listed above. Do you think using an int * would be better than a void * then? (Because word-addressed processors face this different addressing issue only for pointers characters/bytes and void, which is supposed to have a representation identical to characters.) But that also leads me to believe that there wouldn’t be a “true” portable piece to check this across _all_ architectures because even apart from word-addressing, “some” architectures with their own compilers might choose to represent pointers differently. So, we can probably have something that works across the common programming models that one thinks their program would work on (e.g. the ones listed above are the ones that common-workstation processors use)
PS: Your searchable standard and associated commentary is great. I found the statement related to void * representation also on your site.
I’d suggest doing
#include
n = CHAR_BIT * sizeof (void *);
To capture word-addressed machines, where CHAR_BIT will be larger than 8. Silently assuming CHAR_BIT is eight is not a good way to write portable code.
Bleh. The blog engine ate my brackets. Maybe it supports HTML entities? If so, this looks right:
#include <limits.h>
If not, the header to include is limits.h.
@unwind: Thanks for the input. I will update your and Derek’s suggestions to the post in a short while.
PS: I guess you are “The” Emil (of gentoo)?
@Shantanu: The problem with using sizeof is that padding bits/bytes may exist in the type, rendering the result useless. Checking the value of the macros INTPTR_MIN/MAX (in stdint.h) is the only reliable way of obtaining information on the size of pointers.
I don’t quite get the point of the check in the first place. “64-bit” is most of the time marketing blather. I think even today no 64-bit machine has a true 64-bit address and data bus. They can handle at most 48 to 56-bit and the rest is just zero padded. Also, the C compiler doesn’t have to expose or limit itself to the actual hardware architecture. Consider Java which always emulates a 64-bit environment. A C compiler can use an arbitrary ABI with long being 32 or 64 bit regardless of the CPU. See, long long is already an “emulated” integer type on 32-bit architectures, so, for example, modifying such integers cannot be atomic.
It is also not necessarily a good idea to use 64-bit integers on 64-bit architectures. Many people seem to think it will be automatically faster. No, it wasted bandwidth and memory. Heck, it is even an issue when pointers are 64-bit wide. You rarely need more than 2 GiB address space or memory but you’ll always have the overhead. With code heavy on pointer handling, such as linked lists, hash tables, you get twice as much overhead. So it can actually be faster to use indices and limit them to 32 bit or maybe even 16 bit. Modern CPUs are much faster when they can operate on cached or prefetched data. So while it’s not a problem to use much more memory nowadays, it is still a good idea to keep data compact and local to take as much advantage of memory as possible.
Clean code that isn’t “optimized” to death, rarely needs to know sizes of integers or pointers. You just use the sizeof operator and respect the integers’ extreme values instead of making assumptions. Since the compiler knows these compile-time constants and many optimization techniques, well-written code will be optimized without having to do that manually. For example, a mask operation like “& 0xffffU” will be completely skipped for 16-bit integers but if you write it out, your code will still work with 32-bit or 36-bit integers.
@Shantanu: Oh, I got 450 ms of Internet fame!
Amazing … But I think “the” is stretching it a bit. True though, I did write gentoo (the file manager, for picky people who only associate the word with the Linux distro). Glad you know it!
Btw, I find the backslash in “C \ C++” horrible … I find “C/C++” horrible too; they’re two separate languages, may I humbly suggest the word “and”, to cover both?
[...] above snippet will work, but not always (Hint). Many people use a much simplified form, which does not involve any pointer arithmetic: unsigned [...]