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).
Related
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?
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
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
I want a 128 bit integer because I want to store results of multiplication of two 64 bit numbers. Is there any such thing in gcc 4.4 and above?
For GCC before C23, a primitive 128-bit integer type is only ever available on 64-bit targets, so you need to check for availability even if you have already detected a recent GCC version. In theory gcc could support TImode integers on machines where it would take 4x 32-bit registers to hold one, but I don't think there are any cases where it does.
In C++, consider a library such as boost::multiprecision::int128_t which hopefully uses compiler built-in wide types if available, for zero overhead vs. using your own typedef (like GCC's __int128 or Clang's _BitInt(128)). See also #phuclv's answer on another question.
ISO C23 will let you typedef unsigned _BitInt(128) u128, modeled on clang's feature originally called _ExtInt() which works even on 32-bit machines; see a brief intro to it. Current GCC -std=gnu2x doesn't even support that syntax yet.
GCC 4.6 and later has a __int128 / unsigned __int128 defined as a built-in type. Use
#ifdef __SIZEOF_INT128__ to detect it.
GCC 4.1 and later define __int128_t and __uint128_t as built-in types. (You don't need #include <stdint.h> for these, either. Proof on Godbolt.)
I tested on the Godbolt compiler explorer for the first versions of compilers to support each of these 3 things (on x86-64). Godbolt only goes back to gcc4.1, ICC13, and clang3.0, so I've used <= 4.1 to indicate that the actual first support might have been even earlier.
legacy recommended(?) | One way of detecting support
__uint128_t | [unsigned] __int128 | #ifdef __SIZEOF_INT128__
gcc <= 4.1 | 4.6 | 4.6
clang <= 3.0 | 3.1 | 3.3
ICC <= 13 | <= 13 | 16. (Godbolt doesn't have 14 or 15)
If you compile for a 32-bit architecture like ARM, or x86 with -m32, no 128-bit integer type is supported with even the newest version of any of these compilers. So you need to detect support before using, if it's possible for your code to work at all without it.
The only direct CPP macro I'm aware of for detecting it is __SIZEOF_INT128__, but unfortunately some old compiler versions support it without defining it. (And there's no macro for __uint128_t, only the gcc4.6 style unsigned __int128). How to know if __uint128_t is defined
Some people still use ancient compiler versions like gcc4.4 on RHEL (RedHat Enterprise Linux), or similar crusty old systems. If you care about obsolete gcc versions like that, you probably want to stick to __uint128_t. And maybe detect 64-bitness in terms of sizeof(void*) == 8 as a fallback for __SIZEOF_INT128__ no being defined. (I think GNU systems always have CHAR_BIT==8, although I might be wrong about some DSPs). That will give a false negative on ILP32 ABIs on 64-bit ISAs (like x86-64 Linux x32, or AArch64 ILP32), but this is already just a fallback / bonus for people using old compilers that don't define __SIZEOF_INT128__.
There might be some 64-bit ISAs where gcc doesn't define __int128, or maybe even some 32-bit ISAs where gcc does define __int128, but I'm not aware of any.
The GCC internals are integer TI mode (GCC internals manual). (Tetra-integer = 4x width of a 32-bit int, vs. DImode = double width vs. SImode = plain int.) As the GCC manual points out, __int128 is supported on targets that support a 128-bit integer mode (TImode).
// __uint128_t is pre-defined equivalently to this
typedef unsigned uint128 __attribute__ ((mode (TI)));
There is an OImode in the manual, oct-int = 32 bytes, but current GCC for x86-64 complains "unable to emulate 'OI'" if you attempt to use it.
Random fact: ICC19 and g++/clang++ -E -dM define:
#define __GLIBCXX_TYPE_INT_N_0 __int128
#define __GLIBCXX_BITSIZE_INT_N_0 128
#MarcGlisse commented that's the way you tell libstdc++ to handle extra integer types (overload abs, specialize type traits, etc)
icpc defines that even with -xc (to compile as C, not C++), while g++ -xc and clang++ -xc don't. But compiling with actual icc (e.g. select C instead of C++ in the Godbolt language dropdown) doesn't define this macro.
The test function was:
#include <stdint.h> // for uint64_t
#define uint128_t __uint128_t
//#define uint128_t unsigned __int128
uint128_t mul64(uint64_t a, uint64_t b) {
return (uint128_t)a * b;
}
compilers that support it all compile it efficiently, to
mov rax, rdi
mul rsi
ret # return in RDX:RAX which mul uses implicitly
Ah, big integers are not C's forte.
GCC does have an unsigned __int128/__int128 type, starting from version 4.something (not sure here). I do seem to recall, however, that there was a __int128_t def before that.
These are only available on 64-bit targets.
(Editor's note: this answer used to claim that gcc defined uint128_t and int128_t. None of the versions I tested on the Godbolt compiler explorer define those types without leading __, from gcc4.1 to 8.2 , or clang or ICC.)
You could use a library which handles arbitrary or large precision values, such as the GNU MP Bignum Library.
I am about to port a Windows 32 Bit application to 64 Bit, but might decide to port the whole thing to Linux later.
The code contains sections which are dependent on the amount of memory available to the application (which depends on whether I'm creating a 32 or 64 Bit build), while the ability to compile a 32 Bit version of the code should be preserved for backward compatibility.
On Windows, I am able to simply wrap the respective code sections into preprocessor statements to ensure the right version of the code is compiled.
Unfortunately I have very few experience on programming on the Linux platform, so the question occurred:
How am I able to identify a 64 Bit build on the Linux platform?
Is there any (preferably non-compiler-specific) preprocessor define I might check for this?
Thanks in advance!
\Bjoern
Assuming you are using a recent GNU GCC compiler for IA32 (32-bit) and amd64 (the non-Itanium 64-bit target for AMD64 / x86-64 / EM64T / Intel 64), since very few people need a different compiler for Linux (Intel and PGI).
There is the compiler line switch (which you can add to CFLAGS in a Makefile) -m64 / -m32 to control the build target.
For conditional C code:
#if defined(__LP64__) || defined(_LP64)
#define BUILD_64 1
#endif
or
#include <limits.h>
#if ( __WORDSIZE == 64 )
#define BUILD_64 1
#endif
While the first one is GCC specific, the second one is more portable, but may not be correct in some bizarre environment I cannot think of.
At present both should both work for IA-32 / x86 (x86-32) and x86-64 / amd64 environments correctly. I think they may work for IA-64 (Itanium) as well.
Also see Andreas Jaeger's paper from GCC Developer's Summit entitled, Porting to 64-bit GNU/Linux Systems which described 64-bit Linux environments in additional detail.
According to the GCC Manual:
__LP64__
_LP64
These macros are defined, with value 1, if (and only if) the
compilation is for a target where long
int and pointer both use 64-bits and
int uses 32-bit.
That's what you need, right?
Also, you can try
#define __64BIT (__SIZEOF_POINTER__ == 8)