tags:

views:

286

answers:

5

Is there a way to find out if the machine is 32-bit or 64-bit by writing some code in C?

+7  A: 
#include <limits.h>
/* ... */
printf("This machine's pointers to void, in a program "
       "compiled with the same options as this one and "
       "with the same compiler, use %d bits\n",
    (int)sizeof (void*) * CHAR_BIT);
pmg
+1 for using `CHAR_BIT`.
Carl Norum
Completely useless. Compile your program for 32-bit platform and run it on a 64-bit machine. It will never know that the machine is 64-bit.
AndreyT
On top of that, on typical 16-bit C platforms pointers could easily have 32-bit size.
AndreyT
@AndreyT - similarly, when I run an Atari ST program under Steem or a C64 program under Vice64, it never knows that it's running on a PC. That is what emulation and virtual machines are supposed to achieve. But is it a relevant point? There's 32-bit code and 64-bit code, and they are different. The width of a pointer in your object code may well be relevant.
Steve314
@AndreyT: you're right, thank you. `printf` not changed though
pmg
@AnreyT - there are no 16 bit platforms that have 32-bit pointers. Or rather, there are, but only if you mix and match different meanings of the number of bits. The 68000 had a 16 bit data bus and a 16 bit block machine code but 32 bit address registers (and a 24 bit address bus) for instance. In some ways, even amd64 is 8 bit (chunkiness of machine code), yet in other ways even early Pentiums were 64 bit and IIRC Pentium Pros 128 bit (data bus). But the width of a pointer is always the same as the width of a pointer. Except when it's not (e.g. near and far addresses on 16-bit x86) ;-)
Steve314
the real issue is why he wants to know. If he compiles on a 32-bit machine buts runs on a 64 bit machine he may well want to know that his code is running with 32 bit pointers; then its not useless.
pm100
+5  A: 

If by "some code in C" you mean standard C code, then the answer is no, it is not possible. For a C program, the "world" it can see is created entirely by the implementation (by the compiler). The compiler can emulate absolutely any "world", completely unrelated to the underlying hardware.

For example, you can run a 32-bit compiler on a 64-bit machine and you will never be able to detect the fact that this is a 64-bit machine from your program.

The only way you can find out anything about the machine is to access some non-standard facilities, like some OS-specific API. But that goes far beyond the scope of C language.

Needless to add, the already suggested in other answers methods based on sizeof and other standard language facilities do not even come close detect the bit-ness of the machine. Instead they detect the bit-ness of the platform provided by the compiler implementation, which in general case is a totally different thing.

AndreyT
+1 for correctness; however, the properties of this "world" are obviously important as they directly impact the execution of the program and might be what zero4 is looking for; my crystal ball wasn't clear on that one ;)
Christoph
@Christoph - I recently converted my crystal ball from 32 bit to 64 bit. Bad idea. Cut my feet to shreads jumping up and down on the fragments, and ended up with hundreds of bits - which I guess explains why it still doesn't work right. Oh well. Still - I'm looking forward to "upgrading" my PC, just as soon as my feet heal.
Steve314
I think paragraph 2 is blatantly wrong.
Matt Joiner
@Matt Joiner: I don't.
AndreyT
@AndreyT - there are APIs that will tell you what O/S version you're running on and how it's configured. They aren't in the C standard, and are platform-specific, but that doesn't mean a C program can't use them. Why you'd be looking to detect it would be the real question - a 32-bit bootstrap that loads either a 32-bit or 64-bit main implementation might make some sense, but perhaps more sense as an intaller thing than every single time you run it.
Steve314
@Steve314: But that's exactly what my answer states: you can't do it in standard C, but only through an OS-specific API.
AndreyT
@AndreyT - Standard C has the ability to call non-standard libraries and APIs. There is no rule in C that says "a standard C compiler shall only be able to include standard headers" or "a standard C-compliant linker shall only be able to link to standard libraries" nor that "non-standard libraries linked to standard C code must also be written in standard C". It's a childishly pedantic point, but in my experience any disagreement will lead to squabbling over technicalities, and I'll never admit I was so focussed on the second half of the comment that I didn't check the first. Er... whoops!
Steve314
A: 

The pointer size

sizeof (void *) * CHAR_BIT

is a good indicator, but might be misleading on more exotic architectures (eg if the size of the address bus is no multiple of the word size) and only represent the execution environment (which might be different from the actual hardware - see AndreyT's answer).

During the preprocessing phase, the best you can do within the framework of the C language is something like

UINTPTR_MAX == UINT64_MAX

The same limitations as above apply.

Christoph
A: 

Yes, if running on an x86 processor use the CPUID instruction:

http://en.wikipedia.org/wiki/CPUID

drivel
How are you going to do that from C?
Carl Norum
Probably by casting a pointer to a string to a function pointer and trying to call it... ;-)
R..
"How are you going to do that from "C"?": if using Visual Studio: "__cpuid(b,a)"
drivel
+1  A: 

There is no such thing as 32 bit or 64 bit environments, this is just too much of an oversimplification. You have several characteristics of integer, pointer, and float sizes that come into play if you want to write a portable application.

The size of your different integer types can be checked with the appropriate macros such as UINT_MAX etc, pointer size by UINTPTR_MAX. Since there might be padding bits, to deduce the width of the types you should print something like (unsigned long long)(T)-1 where T is an unsigned type.

Jens Gustedt