Porting 64bit code to 32bit machine - c

I have seen many people asking porting issues from 32bit to 64bit machine. But is it not common to port code written on 64bit to 32bit. I am trying to port a plugin from 64bit to 32bit in C,but facing similar issues in cases like storing void * to 64bit integers and vice versa.
Whats should be approach in changing the code such that same code works on both(i386 & x86_64) machines? I don't think it make sense to use uint64_t * on a 32 bit machine in place of void* which is 32bit? Does some generalized approach exists for such cases?

Pointers should never be stored in fixed-size integers. If you need to store a pointer in an integer type, the correct type is uintptr_t, but you really should not be storing pointers in integer objects at all. However, there's no real harm in using an integer type that's too large; it will just waste a little bit of memory. So if storing pointers in uint64_t is the only issue in your code, it should work fine compiled for 32-bit targets.

As you know, You can write one source code for both 32bit and 64bit architectures with a series of "#define", "#ifdef" etc which are pre-processor directives. You need to compile the source once for 32bit and 64bit each. This can be something like this.
test.c sample code
#ifdef ARCH_64
typedef UINT unit64_t;
#else
typedef UINT unit32_2;
UINT *my_uint_ptr;
$ gcc -m32 test.c
$ gcc -m64 -DARCH_64 test.c

Related

Share C code containing uint64_t between 64-bit and 32 bit systems

I am creating some C code for an intel 8052AH CPU, which I believe is 32-bits wide. I would like to share some C code written for a PC that is 64-bits wide.
In my PC program I define a number of C structs that I would like to share with my 8052AH C code. Obviously the uint64_t used in the structs of PC code causes a compilation error on the Keil C51 compiler.
What is the best way to share my structs? I am thinking about creating a typedef for uint64_t that maps to char[8] on the 8052 C code. Is there a Keil C51 specific way to do this? Is there a better generic way to do this?

Different sizeof(long) values in W7 and Linux Mint

IDE: Code::Blocks 13.12
Compiler: GNU GCC
Application type: console application
Language: C
Platforms: W7 and Linux Mint
I wrote a compiler and interpreter for a self defined language, I made executables for Windows and Linux. The compiler - obviously - generates a code file that is read by the interpreter. I want to use the compiled file both on Windows and Linux. So, a file created with the Windows compiler must be readable by the Linux interpreter and vice versa.
I can't get the compatibility to work. I found that in Windows, the sizeof(long)=4 and in Linux, sizeof(long)=8. As the compiler will write long integers to the output file I think the difference in size is (part of) the problems I have.
I checked this forum, but similar problems are mostly about casting and writing platform independent C++ code. I also found some suggestions about using (u)intptr_t but these are also pointer related.
Maybe the quickest solution is to use type int rather than long in Linux, but then I would have different sourcecode for both platforms.
Is there another way to handle this issue?
Consider using int32_t for a 32 bit 2's complement signed integral type, and int64_t for a 64 bit 2's complement signed integral type.
Note that a compiler doesn't have to support these types, but if it does then they must be as I describe.
An int in C can be as small as -32767 to +32767. A long must be at least 32 bit. MSVC maintains a long as 32 bit on 64 bit systems (it uses the LLP64 model). The C standard does not place an upper limit on the sizes. This flexibility allows optimal C compilation on a variety of platforms.
If you want to have a specific size used a type with the size suffix in it like uint64_t.The size of a long integer varies between architectures and operating systems.
Reference Link:https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models

How to check if the machine running on is 32 or 64 bit in C?

is there any preprocessor directive or other methods to check if the machine being run is 32 bit or 64 bit in C? I've tried googling this, but the problem with C is it brings up results for C#, C++, etc.. Also, I would prefer if this worked on Windows, Linux, and Mac.
The obvious way to do this at run time.
#include <limits.h>
#include <stdio.h>
int main()
{
printf("%d bits\n", (int)(CHAR_BIT * sizeof(void *)));
return 0;
}
Technically, this is not 100% guaranteed to work. Practically, this will work with most modern compilers - it is unusual for a void pointer to be represented using a number of bits that differs from that of the underlying system architecture.
To do a compile time check, there is no standard way. It is necessary to resort to macros that are specific to your compiler/preprocessor. You will therefore need to read relevant documentation.
For Linux and OS X:
#include <sys/utsname.h>
struct utsname a;
uname (&a);
a->machine will be the string x86_64 on 64bit Intel machines, probably i586 or i686 on 32bit. You could do conditional compiling for these and whatever Windows uses.
This isn't necessarily indicative of the machine that is running (read: not true when cross-compiling), but there are some preprocessor directives.
You can determine 32/64 bit from the architecture, the most common ones are:
// 64-bit
__x86_64__
// 32-bit
__i386__ ... __i686__
You can read a whole bunch of these here, for nearly any modernish processor:
http://sourceforge.net/p/predef/wiki/Architectures/
If this worked on Windows, I have some method.
check whether the reg HKEY_CURRENT_USER\Software\Wow6432Node exists;
check whether the file C:\Windows\SysWOW64 exists;
use Windows API(IsWow64Process), please read MSDN.
You can use the following preprocessor directives to check if the machine is x86_64 in C. If it is 64-bit it sets the #define BUILD_64 flag. You then just check #ifdef BUILD_64 as the test throughout your code:
#if defined(__LP64__) || defined(_LP64)
# define BUILD_64 1
#endif

Is the -mx32 GCC flag implemented (correctly)?

I am trying to build a program that communicates with a 32-bit embedded system, that runs on a Linux based x86_64 machine (host). On the host program I have a structure containing a few pointers that reflects an identical structure on the embedded system.
The problem is that on the host, pointers are natively 64-bits, so the offset of the structure members is not the same as in the embedded system. Thus, when copying the structure (as memcpy), the contents end up at the wrong place in the host copy.
struct {
float a;
float b;
float *p;
float *q;
} mailbox;
// sizeof(mailbox) is 4*4=16 on the embedded, but 2*4+2*8=24 on the host
Luckily, I found out here that gcc has an option -mx32 for generating 32-bit pointers on x86_64 machines. But, when trying to use this, I get an error saying:
$ gcc -mx32 test.c -o test.e
cc1: error: unrecognized command line option "-mx32"
This is for gcc versions 4.4.3 and 4.7.0 20120120 (experimental).
Why doesn't this option work? Is there a way around this?
EDIT: Accrding to the v4.4.7 manual, there was no -mx32 option available, and this is true up to v4.6.3. OTOH, v4.7.0 does show that option, so it may be that the Jan-20 version I am using is not the final one?!
Don't do this. First, x32 is a separate architecture. It's not merely a compiler switch. You need an x32 version of every library you link against to make this work. Linux distros aren't yet producing x32 versions, so that means you'll be either linking statically or rolling your own library environment.
More broadly: that's just asking for trouble. If your structure contains pointers they should be pointers. If it contains "32 bit addresses" they should be a 32 bit integer type.
You might need a newer version of binutils
Though I think gcc 4.8 is recommended
But in general you need a kernel compiled multilib with it: https://unix.stackexchange.com/questions/121424/linux-and-x32-abi-how-to-use

128 bit integer with c on windows?

Is there any c compiler on windows able to use 128 bit integers natively?
On example, you can use gcc on linux, with __uint128_t... any other chance on windows?
(It would be great if 128 bit worked on 32 bit computers as well! :D)
Matteo
In GCC you can try __attribute__((mode(...))), see here and here, e.g.
typedef unsigned int myU128 __attribute__((mode(TI)));
The results depend on your platform, though.
You could try using SSE intrinsics built into Visual C++
http://msdn.microsoft.com/en-us/library/5eawz414%28v=VS.80%29.aspx (Look at the __m128 type).

Resources