C: Difference between U64 and uint64_t - c

I am trying to learn C after working with Java for a couple of years.
I've found some code that I wanted to reproduce which looked something like this:
U64 attack_table[...]; // ~840 KiB
struct SMagic {
U64* ptr; // pointer to attack_table for each particular square
U64 mask; // to mask relevant squares of both lines (no outer squares)
U64 magic; // magic 64-bit factor
int shift; // shift right
};
SMagic mBishopTbl[64];
SMagic mRookTbl[64];
U64 bishopAttacks(U64 occ, enumSquare sq) {
U64* aptr = mBishopTbl[sq].ptr;
occ &= mBishopTbl[sq].mask;
occ *= mBishopTbl[sq].magic;
occ >>= mBishopTbl[sq].shift;
return aptr[occ];
}
U64 rookAttacks(U64 occ, enumSquare sq) {
U64* aptr = mRookTbl[sq].ptr;
occ &= mRookTbl[sq].mask;
occ *= mRookTbl[sq].magic;
occ >>= mRookTbl[sq].shift;
return aptr[occ];
}
The code is not that important but I already failed at using the same datatype: U64, I only found uint64_t. Now I would like to know where the difference in U64, uint64_t and long is.
I am very happy if someone could briefly explain this one to me, including the advantage of each of them.
Greetings,
Finn

TL;DR - for a 64-bit exact width unsigned integer, #include <stdint.h> and use uint64_t.
Presumably, U64 is a custom typedef for 64-bit wide unsigned integer.
If you're using at least a C99 compliant compiler, it would have <stdint.h> with a typedef for 64-bit wide unsigned integer with no padding bits: uint64_t. However, it might be that the code targets a compiler that doesn't have the standard uint64_t defined. In that case, there might be some configuration header where a type is chosen for U64. Perhaps you can grep the files for typedef.*U64;
long on the other hand, is a signed type. Due to various undefined and implementation-defined aspects of signed math, you wouldn't want to use a signed type for bit-twiddling at all. Another complication is that unlike in Java, the C long doesn't have a standardized width; instead long is allowed to be only 32 bits wide - and it is so on most 32-bit platforms, and even on 64-bit Windows. If you ever need exact width types, you wouldn't use int or long. Only long long and unsigned long long are guaranteed to be at least 64 bits wide.

Related

int_fast_ types and value overflow

If I understand well, int_fast_n_t types are guaranteed to be at least n bits long. Depending on the compiler and the architecture of the computer these types can also be defined on more than n bits. For instance, a int_fast_8_t could be interpreted as a 32 bits int.
Is there some kind of mechanism which enforces that the value of an int_fast_n_t never overflow even if the true type is defined on more than n bits?
Consider the following code for example:
int main(){
int_fast8_t a = 64;
a *= 2; // -128
return 0;
}
I do not want a to be greater than 127. If a is interpreted as a "regular" int (32 bits), is it possible that a exceed 127 and be not equal to -128?
Thanks for your answers.
int_fast8_t a = 64;
a *= 2;
If a is interpreted as a "regular" int (32 bits), is it possible that a exceed 127 and be not equal to -128?
Yes. It very likely a * 2 will save in a as 128. I would expect this on all processors unless the processor was an 8-bit one.
Is there some kind of mechanism which enforces that the value of an int_fast_n_t never overflow ?
No. Signed integer overflow is still possible as well as values outside the [-128...127] range.
I do not want a to be greater than 127
Use int8_t. The value save will never exceed 127, yet code still has implementation defined behavior in setting a 128 to an int8_t. This often results in -128 (values wrap mod 256), yet other values are possible (this is uncommon).
int8_t a = 64;
a *= 2;
If assignment to int8_t is not available or has unexpected implementation defined behavior, code could force the wrapping itself:
int_fast8_t a = foo(); // a takes on some value
a %= 256;
if (a < -128) a += 256;
else if (a > 127) a -= 256;
It is absolutely possible for the result to exceed 127. int_fast8_t (and uint_fast8_t and all the rest) set an explicit minimum size for the value, but it could be larger, and the compiler will not prevent it from exceeding the stated 8 bit bounds (it behaves exactly like the larger type it represents, the "8ness" of it isn't relevant at runtime), only guarantee it can definitely represent all values in said 8 bit range.
If you need it to explicitly truncate/wrap to 8 bit values, either use (or cast to) int8_t to restrict the representable range (though overflow wouldn't be defined), or explicitly use masks to perform the same work yourself when needed.
Nope. All the fast types really are are typedefs. For example, stdint.h on my machine includes
/* Fast types. */
/* Signed. */
typedef signed char int_fast8_t;
#if __WORDSIZE == 64
typedef long int int_fast16_t;
typedef long int int_fast32_t;
typedef long int int_fast64_t;
#else
typedef int int_fast16_t;
typedef int int_fast32_t;
__extension__
typedef long long int int_fast64_t;
#endif
/* Unsigned. */
typedef unsigned char uint_fast8_t;
#if __WORDSIZE == 64
typedef unsigned long int uint_fast16_t;
typedef unsigned long int uint_fast32_t;
typedef unsigned long int uint_fast64_t;
#else
typedef unsigned int uint_fast16_t;
typedef unsigned int uint_fast32_t;
__extension__
typedef unsigned long long int uint_fast64_t;
#endif
The closest you can come without a significant performance penalty is probably casting the result to an 8-bit type.
Just use unsigned char if you want to manipulate 8 bits (unsigned char is one byte long) you will work on 0 to 0xFF (255) unsigned range
From the C(99) standard:
The typedef name intN_t designates a signed integer type with width N
, no padding bits, and a two’s complement representation. Thus, int8_t
denotes a signed integer type with a width of exactly 8 bits.
So use int8_t to guarantee 8 bit int.
A compliant C99/C11 compiler on a POSIX platform must have int8_t.

How to make signed 64 bit integer using one signed integer and one unsigned integer on 32 bit processor

On 32 bit processor with 32 bit compiler I want to make a 64 bit signed integer using one of each signed and unsigned integer. Without using any predefined macro or types.
32-bit compilers will handle 64-bit numbers for you. So its unlikely you actually need this. But I'll bite. On the surface this is a pretty simple problem.
#include <stdint.h>
static inline int64_t make_int64(uint32_t low, int32_t high) {
return (int64_t)((uint64_t)high << 32) | low;
}
static inline void split_int64(int64_t value, uint32_t *low, int32_t *high) {
*low = value & 0xFFFFFFFF;
*high = (int32_t)((uint32_t)(value >> 32));
}
But its always tricky/dangerous mixing signed and unsigned integers. Manually constructing an int also requires you to know how the processor formats them. We'll assume its 2s compliment little endian.
It would be helpful if you gave a full description of your requirements. For example the above example make_int64(0, -1) = -4294967296 but make_int64(1, -1) = -4294967295.

Is there a way to specify int size in C?

I'm trying to check some homework answers about overflow for 2's complement addition, subtraction, etc. and I'm wondering if I can specify the size of a data type. For instance if I want to see what happens when I try to assign -128 or -256 to a 7-bit unsigned int.
On further reading I see you wanted bit sizes that are not normal ones, such as 7 bit and 9 bit etc.
You can achieve this using bitfields
struct bits9
{
int x : 9;
};
Now you can use this type bits9 which has one field in it x that is only 9 bits in size.
struct bits9 myValue;
myValue.x = 123;
For an arbitrary sized value, you can use bitfields in structs. For example for a 7-bit value:
struct something {
unsigned char field:7;
unsigned char padding:1;
};
struct something value;
value.field = -128;
The smallest size you have have is char which is an 8 bit integer. You can have unsigned and signed chars. Take a look at the stdint.h header. It defines a int types for you in a platform independent way. Also there is no such thing as an 7 bit integer.
Using built in types you have things like:
char value1; // 8 bits
short value2; // 16 bits
long value3; // 32 bits
long long value4; // 64 bits
Note this is the case with Microsoft's compiler on Windows. The C standard does not specify exact widths other than "this one must be at least as big as this other one" etc.
If you only care about a specific platform you can print out the sizes of your types and use those once you have figured them out.
Alternatively you can use stdint.h which is in the C99 standard. It has types with the width in the name to make it clear
int8_t value1; // 8 bits
int16_t value2; // 16 bits
int32_t value3; // 32 bits
int64_t value4; // 64 bits

Hi-Tech C Compiler struct of bits

I am using the MPLAB X IDE with Hi-Tech C Compiler on an PIC-controller.
Therefore it is important ti thing a little bit "Byte-orientated".
So I try the following:
volatile struct{
unsigned bit white:1;
unsigned bit red:1;
unsigned bit blue:1;
unsigned bit green:1;
unsigned bit violett:1;//Magenta
unsigned bit yellow:1;
}ColorPick;
Now I am not sure if it is declared correctly and What happens, when I drop some Bit-Shifting over that.
In My Result it should only be one bit aktive (1) and all other low (0).
So is "white the bit 0b00000001 or 0b10000000 ?
And when I shift it 6 times I will get yellow. And after that white again.
Can I do that in an identically funktion call of ColorPick << 1; ?
I guess the 1 get shifted to bit 7 and 8 I did not declared as such.
How can I correct this?
From the Hi-Tech C User Manual, page 346:
A.9.4 The order of allocation of bit-fields within an int (6.5.2.1)
The first bit-field defined in a structure is allocated the least
significant bit position in the storage unit. Subsequent bit-fields
are allocated higher-order bits.
Based on the documentation, I don't think that bit is a keyword in your compiler.
It has been my experience that bitfields are compiler dependent. The way I determine the bit alignments is to write a little command line program that does something like this:
union test_u {
struct test_s {
unsigned long bwhite : 1;
unsigned long bred : 1;
unsigned long bblue : 1;
unsigned long bgreen : 1;
unsigned long bviolet : 1;
unsigned long byellow : 1;
unsigned long bpink : 1;
} bits;
unsigned long unlong;
} bitest;
bitest.unlong = 0;
bitest.bred = 1;
printf("0x%8.8X\n", bitest.unlong);
Then substitute values in as needed to see where your compiler sticks them. If you need to communicate with other computers/compilers, you would probably be better off using masks and shifts yourself.

Which initializer is appropriate for an int64_t?

I like to initialize my variables to some "dummy" value and have started to use int64_t and uint64_t. So far, it looks like there are at least three ways I could initialize an int64_t to a particular value (and with slight changes for the unsigned equivalent):
int64_t method_one = 0;
int64_t method_two = 0LL;
int64_t method_three = INT64_C(0);
I use GCC and target OS X and Linux. I'd like to pick a method that aims for ease of portability and clarity — but correctness, above all. Am I overthinking this, or is there a "best" or "most recommended" approach for initializing this variable type, for any particular value I throw at it (which is within its bounds, of course)?
int64_t method_one = 0;
...is perfectly reasonable. C99 (see e.g. draft here; yes, I know it's not the most recent standard any more, but it's the one that introduced the int<N>_t types) says that:
the 0 has type int (§6.4.4.1 para.5);
the type of the expression is int64_t (§6.5.16 para.3);
the type of the right-hand side will be converted to the type of the expression (§6.5.16.1 para.2);
this conversion will not change the value (§6.3.1.3 para.1).
So there's nothing wrong with that at all, and the lack of additional clutter makes it the most readable of the options when initialising to 0 or anything else in the range of an int.
int64_t method_two = 0LL;
int64_t is not guaranteed to be the same as long long; however, this should in fact work portably for any signed 64-bit value as well (and similarly ULL for unsigned 64-bit values): long long (and unsigned long long) should be at least 64 bits in a C99-compliant implementation (§5.2.4.2.1), so LL (and ULL) should always be safe for initialising 64-bit values.
int64_t method_three = INT64_C(0);
This is arguably a better option for values which may be outside the range of an int, as it expresses the intent more clearly: INT64_C(n) will expand to something appropriate for any n in (at least) a 64-bit range (see §7.18 in general, and particularly §7.8.4.1).
In practice, I might well use any of the above, depending on context. For example:
uint64_t counter = 0;
(Why add unnecessary clutter?)
uint64_t some_bit = 1ULL << 40;
(1 << 40 simply won't work unless int is unusually wide; and UINT64_C(1) << 40 seems less readable to me here.)
uint64_t some_mask = UINT64_C(0xFF00FF00FF00FF00);
(In this case, explicitly calling out the value as a 64-bit constant seems more readable to me than writing 0xFF00FF00FF00FF00ULL.)
Personnally, I would use the third, which is the most portable way to achieve this.
#include <stdint.h>
int64_t method_three = INT64_C(0);
uint64_t method_three = UINT64_C(0);
Anyway, I don't think it's a very important thing.
According to the ANSI C standard, the suffix for a long long int and unsigned long long int is LL and ULL respectively:
octal or hexadecimal suffixed by ll or LL long long int, unsigned
long long int decimal, octal, or hexadecimal suffixed by both u or U,
and ll or LL unsigned long long int
If you know that int64_t is defined as:
typedef signed long long int int64_t
Then method two is most definitely the correct one:
int64_t method_two = 0LL;
uint64_t method_two = 0ULL;
Edit:
Keeping in mind the portability issues, and the fact that it's not guaranteed to be defined as long long, then it would be better to use the third method:
INT64_C()
UINT64_C()

Resources