简体   繁体   中英

Standard (cross-platform) way for bit manipulation

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

  • zero
  • positive
  • negative?

What does the Standard say about this?

PS 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

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. Eg, 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 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 / 2 E2 . If E1 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:

Bitwise manipulations on integers are not portable.

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 is E1 left-shifted E2 bit positions; vacated bits are zero-filled. If E1 has an unsigned type, the value of the result is E1 × 2 E2 , reduced modulo one more than the maximum value representable in the result type. Otherwise, if E1 has a signed type and non-negative value, and E1×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 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a non-negative value, the value of the result is the integral part of the quotient of E1/2 E2 . If E1 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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM