Reputation: 38143
As are are different binary representation of the numbers (for example, take big/little endian), is this cross-platform:
// NOTE: FIXED-SIZE unsigned integral type
some_unsigned_type variable = some_number;
// set n-th bit, starting from 1,
// right-to-left (least significant-to most significant)
variable |= ( 1 << ( n - 1 ) );
// clear the same bit:
variable &= ~( 1 << ( n - 1 ) );
In other words, does the compiler always take care of the different binary representation of the fixed size unsigned numbers, or it's platform-specific?
And what if variable
is signed integral type (for example, int
) and its value is
What does the Standard say about this?
P.S. And, yes, I'm interesting in both - C
and C++
, please don't tell me they are different languages, because I know this :)
I can paste real example, if needed, but the post will become too long
Upvotes: 12
Views: 1928
Reputation: 299730
Disclaimer: I am implicitly assuming that you are talking about an integer type with a fixed width. Bit-shifting otherwise is quite hazardous...
Standard: n3337 C++11
The definition of shifts is mathematical for unsigned types or positive values in signed types (*), and therefore not affected by the underlying hardware representation.
5.8 Shift operators [expr.shift]
2 The value of
E1 << E2
isE1
left-shiftedE2
bit positions; vacated bits are zero-filled. IfE1
has an unsigned type, the value of the result isE1 × 2
E2
, reduced modulo one more than the maximum value representable in the result type. Otherwise, ifE1
has a signed type and non-negative value, andE1×2
E2
is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.3 The value of
E1 >> E2
isE1
right-shiftedE2
bit positions. IfE1
has an unsigned type or ifE1
has a signed type and a non-negative value, the value of the result is the integral part of the quotient ofE1/2
E2
. IfE1
has a signed type and a negative value, the resulting value is implementation-defined.
For the same reason, I would think the bitwise and
, or
and negate
are okay: they are defined mathematically.
5.3.1 Unary operators [expr.unary.op]
10 The operand of
˜
shall have integral or unscoped enumeration type; the result is the one’s complement of its operand.5.11 Bitwise AND operator [expr.bit.and]
1 The usual arithmetic conversions are performed; the result is the bitwise AND function of the operands. The operator applies only to integral or unscoped enumeration operands.
5.13 Bitwise inclusive OR operator [expr.or]
1 The usual arithmetic conversions are performed; the result is the bitwise inclusive OR function of its operands. The operator applies only to integral or unscoped enumeration operands.
However I will admit I am less sure for the latter two, I could not find any definition of bitwise XX function, so even though I believe they refer to they mathematical counterparts I can offer no assurance.
(*) Thanks to phresnel for pointing that out.
Upvotes: 5
Reputation: 308
It's implementation specific if you shift negative (or signed) numbers (through most implementations are the same U2 thing). It's portable for most uses if you shift unsigned numbers by values not exceeding the number of bits in variable.
Upvotes: 1
Reputation: 39089
Unless some_unsigned_type
is a fixed-width type, this is your first platform specific. On one platform, you may be shifting out some information that can never recur by the value itself, while on another it may not. Example:
16 bit 'int':
1000 0000 0000 0000
<<1 = 0000 0000 0000 0000
>>1 = 0000 0000 0000 0000
32 bit 'int':
0000 0000 0000 0000 1000 0000 0000 0000
<<1 = 0000 0000 0000 0001 0000 0000 0000 0000
>>1 = 0000 0000 0000 0000 1000 0000 0000 0000
5.8 Shift Operators
in the C++ standard also says this:
The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand.
So if you shift an integer by more bits than there are, you enter undefined behaviour. E.g., if you left-shift a short
value by 17 bits, it may give you UB on some machines, but not all.
C11 says in 6.5.7 Bitwise shift operators
, apart from other things, this:
The result of
E1 >> E2
isE1
right-shiftedE2
bit positions. IfE1
has an unsigned type or ifE1
has a signed type and a nonnegative value, the value of the result is the integral part of the quotient ofE1 / 2
E2
. IfE1
has a signed type and a negative value, the resulting value is implementation-defined.
So signed-number shifting is not portable.
So, the general answer for integers in general is:
Upvotes: 7