I'm currently working on a project, in which I need bit sets. I'm using an array of uint64_t
's for the bitset.
My current problem is, that whenever I want to set or check a bit I need to do an operation like this:
uint64_t index = 42;
bArr[index/64] |= (((uint64_t)1)<<(index%64));
I can rewrite the division and modulo with some clever and and bitshift operations as well, but I'm concerned about the cast of 1
. I need this cast, since otherwise the 1
is seen as a 32-bit unit. As seen in this example - you get wrong output without a cast:
uint64_t bArr[4]; // 256 bits
bArr[0] = bArr[1] = bArr[2] = bArr[3] = 0; // Set to 0
uint64_t i = 255;
bArr[i/64] = (bArr[i/64] | (((uint64_t)1)<<(i%64)));
uint32_t i2;
for (i2 = 0; i2 < 256; i2++) {
if ((bArr[i2/64] & (((uint64_t)1)<<(i2%64))) != 0) {
printf("bArray[%" PRIu32 "] = 1\n", i2);
}
}
Can I get around this cast in a clever way? I was thinking that the performance is probably suffering from a cast at every read/write...
The result type of <<
operator is the type of the left operand (after integer promotions) that's why you need to use the correct type: 1
is of type int
but you need type uint64_t
.
You can use either:
(uint64_t) 1
or
UINT64_C(1) /* you have to include <stdint.h> */
or
1ULL
(for the last one assuming unsigned long long
is 64-bit in your system which is very likely).
But they are all equivalent: all these expressions are integer constant expressions and their value is computed at compile time and not at run time.
A cast in and of itself does not affect performance. It's a compile time construct that tells the compiler the type of an expression.
In this case, they're all integer casts and expressions, so there should be no performance impact.
C offer macros for this which will expand the integer constant to the type int_leastN_t
.
INTN_C(value)
UINTN_C(value)
Example
#include <stdint.h>.
bArr[index/64] |= UINT64_C(1) << (index%64);
In general it is better to avoid casting. Sometimes casting unexpectedly make the expression narrower than hoped.
Benefit of UINT64_C
: uint_least_64_t/int_least_64_t
types must exist (C99). int64_t/uint64_t
are optional.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With