Reputation: 846
My understanding is that certain bitwise operations on the regular ol' short/int/long types are either implementation-dependent ( | & ~ >> ) or undefined ( << )
However, C99 introduced the fixed-width integer types and explicitly defines them to be two's-complement exact-bitness with no padding bits.
Does that mean that all the bitwise operations are well-defined and portable for those types among platforms that provide them?
For example, this Works on My Machine™, but is it guaranteed to work?
#include <inttypes.h>
#include <stdio.h>
int main() {
uint16_t a = 0xffff;
int16_t b = *(int16_t*)(&a);
printf("%" PRId16 "\n", b);
// Prints '-1'
b <<= 4;
printf("%" PRId16 "\n", b);
// Prints '-16'
return 0;
}
Upvotes: 2
Views: 149
Reputation: 223739
Using the fixed width types does not guarantee protection from undefined behavior related to bit shifting. Section 7.20.1.1 of the C standard regarding exact width integer types states:
1 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 such a signed integer type with a width of exactly 8 bits.2 The typedef name
uintN_t
designates an unsigned integer type with width N and no padding bits. Thus,uint24_t
denotes such an unsigned integer type with a width of exactly 24 bits.3 These types are optional. However, if an implementation provides integer types with widths of 8, 16, 32, or 64 bits, no padding bits, and (for the signed types) that have a two’s complement representation, it shall define the corresponding typedef names.
Nothing here mentions special treatment regarding the behavior of bit shift operations on these types.
One important aspect here is integer promotion. For fixed width types that are smaller than int
, they will first be promoted to int
(not int16_t
or int32_t
) before being applied to most operands. Then you're dealing with potential undefined behavior.
For example, assuming a 32 bit int
, this code exhibits undefined behavior:
uint24_t x = 0xffffff;
uint24_t y = x << 8;
Because in the expression x << 8
, the value of x
is promoted to int
, then the shift causes a bit to be shifted into the sign bit of that value.
Upvotes: 5