4

Is there a simple way to compile 32-bit C code into a 64-bit application, with minimal modification? The code was not setup to use fixed type sizes.

I am not interested in taking advantage of 64-bit memory addressing. I just need to compile into a 64-bit binary while maintaining 4 byte longs and pointers.

Something like:

#define long int32_t

But of course that breaks a number of long use cases and doesn't deal with pointers. I thought there might be some standard procedure here.

Jim
  • 63
  • 3
  • 11
    Properly written portable code will compile and run correctly with zero modification. On the other hand, code that makes assumptions about the sizes of ints can be a nightmare to port to any other environment. I thought we all learned that lesson the hard way 20+ years ago. – President James K. Polk Jun 29 '11 at 23:02
  • 1
    What platform are you working on? – Ken Wayne VanderLinde Jun 29 '11 at 23:03
  • @Greg: it's way too easy to ignore, or even hide, compiler warnings :( – pmg Jun 29 '11 at 23:04
  • 4
    @pmg: I'm just the opposite. I regard a compiler warning as a personal insult and will do anything to make the compiler happy :) – President James K. Polk Jun 29 '11 at 23:05
  • Unfortunately I don't have a choice with the code I was given. I am on OS X (x86_64). – Jim Jun 29 '11 at 23:07
  • @Mark - what "breaks"? Why do you want to redefine `long` when talking about pointers? Your question doesn't make much sense... – littleadv Jun 29 '11 at 23:20
  • On the two large C codebases I have that are sensitive to bitness in certain areas I bit the bullet and spent the time including `stdint.h` and converting them to use `int32_t` if I wasn't able to fix it. If you have code that requires 4 byte `int`/`long` it likely makes poor assumptions you have to fix and these take a lot of time. – user7116 Jun 29 '11 at 23:20
  • @Mark: missed the bit about 4 byte pointers...you can't have that in a 64-bit C executable. By definition they are 64-bits! Why not compile for 32-bit and run it if you don't care about the memory... – user7116 Jun 29 '11 at 23:21

3 Answers3

3

There seem to be two orthogonal notions of "portability":

  1. My code compiles everywhere out of the box. Its general behaviour is the same on all platforms, but details of available features vary depending on the platform's characteristics.

  2. My code contains a folder for architecture-dependent stuff. I guarantee that MYINT32 is always 32 bit no matter what. I successfully ported the notion of 32 bits to the nine-fingered furry lummoxes of Mars.

In the first approach, we write unsigned int n; and printf("%u", n) and we know that the code always works, but details like the numeric range of unsigned int are up to the platform and not of our concern. (Wchar_t comes in here, too.) This is what I would call the genuinely portable style.

In the second approach, we typedef everything and use types like uint32_t. Formatted output with printf triggers tons of warnings, and we must resort to monsters like PRI32. In this approach we derive a strange sense of power and control from knowing that our integer is always 32 bits wide, but I hesitate to call this "portable" -- it's just stubborn.

The fundamental concept that requires a specific representation is serialization: The document you write on one platform should be readable on all other platforms. Serialization is naturally where we forgo the type system, must worry about endianness and need to decide on a fixed representation (including things like text encoding).

The upshot is this:

  • Write your main program core in portable style using standard language primitives.
  • Write well-defined, clean I/O interfaces for serialization.

If you stick to that, you should never even have to think about whether your platform is 32 or 64 bit, big or little endian, Mac or PC, Windows or Linux. Stick to the standard, and the standard will stick with you.

Community
  • 1
  • 1
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
2

No, this is not, in general, possible. Consider, for example, malloc(). What is supposed to happen when it returns a pointer value that cannot be represented in 32 bits? How can that pointer value possibly be passed to your code as a 32 bit value, that will work fine when dereferenced?

This is just one example - there are numerous other similar ones.

Well-written C code isn't inherently "32-bit" or "64-bit" anyway - it should work fine when recompiled as a 64 bit binary with no modifications necessary.


Your actual problem is wanting to load a 32 bit library into a 64 bit application. One way to do this is to write a 32 bit helper application that loads your 32 bit library, and a 64 bit shim library that is loaded into the 64 bit application. Your 64 bit shim library communicates with your 32 bit helper using some IPC mechanism, requesting the helper application to perform operations on its behalf, and returning the results.

The specific case - a Matlab MEX file - might be a bit complicated (you'll need two-way function calling, so that the 64 bit shim library can perform calls like mexGetVariable() on behalf of the 32 bit helper), but it should still be doable.

caf
  • 233,326
  • 40
  • 323
  • 462
  • I thought there may be some compatibility layer you could use that replaces malloc with a malloc that only returns 32-bit pointers. – Jim Jun 29 '11 at 23:35
  • @Mark: That compatibility layer is what you get when you run a 32 bit binary on a 64 bit system. If that's what you want, then just continue to compile 32 bit binaries. – caf Jun 29 '11 at 23:39
  • Unfortunately I need the binary to be 64-bit in order to be loaded by another 64-bit application. This is a matlab mex file. – Jim Jun 29 '11 at 23:46
  • @Mark: Then the basic problem reasserts itself, because even if you had pseudo-64-bit implementations of the C library functions like `malloc()`, there is still no way to tell Matlab that it can only pass 32 bit pointers to your library. See the update at the end of my answer for a possible solution, though. – caf Jun 30 '11 at 00:32
0

The one area that will probably bite you is if any of your 32-bit integers are manipulated bit-wise. If you assume that some status flags are stored in a 32-bit register (for example), or if you are doing bit shifting, then you'll need to focus on those.

Another place to look would be any networking code that assumes the size (and endian) of integers passed on the wire. Once those get moved into 64-bit ints you'll need to make sure that you don't lose sign bits or precision.

Structures that contain integers will no longer be the same size. Any assumptions about size and alignment need to be cleaned out.

jbruni
  • 1,238
  • 8
  • 12