Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does C++14 define the behavior of bitwise operators on the padding bits of unsigned int?

C++ standard

If a C++14 implementation includes padding bits in the underlying bytes of an unsigned int , does the standard specify if bitwise operations must not be performed on padding bits ?

Additionally, does the C++14 standard specify if equality and relational operators must ignore the padding bits ?

Guidelines

If there is a lack of specification on that matter, is there some kind of consensus on the expected behavior of those operators on padding bits?

I found conflicting answers on Stack Overflow. Lightness Races in Orbit and ecatmur say that bitwise operators are unsuitable for arithmetic because they are applied on all bits (including padding bits), while Christoph and Bartek Banachewicz say that the bitwise operators work on the logical value of integers and ignore padding.

References

Related answers: on the existence of padding bits (1, 2, 3), on the absence of clear C++ specification (4).

Definition of padding bits in C++14 - § 3.9.1 - Fundamental types:

For narrow character types, all bits of the object representation participate in the value representation. For unsigned narrow character types, all possible bit patterns of the value representation represent numbers. These requirements do not hold for other types.

Definition of object representation and value representation in C++14 - § 3.9 - Types:

The object representation of an object of type T is the sequence of N unsigned char objects taken up by the object of type T, where N equals sizeof(T). The value representation of an object is the set of bits that hold the value of type T. For trivially copyable types, the value representation is a set of bits in the object representation that determines a value, which is one discrete element of an implementation-defined set of values.44

Footnote 44) The intent is that the memory model of C++ is compatible with that of ISO/IEC 9899 Programming Language C.

Definition of bitwise AND in C++14 - § 5.11 - Bitwise AND operator:

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.

Definition of addition in C++14 - § 5.7 - Additive operators:

The usual arithmetic conversions are performed for operands of arithmetic or enumeration type. For addition, [...] both operands shall have arithmetic or unscoped enumeration type [...]. The result of the binary + operator is the sum of the operands.

like image 507
RalphS Avatar asked Jan 18 '18 22:01

RalphS


People also ask

What is padding bit?

Bit padding is the addition of one or more extra bits to a transmission or storage unit to make it conform to a standard size. Some sources identify bit padding as a type of bit stuffing.

What is bitwise negation operator in C++?

The ~ (bitwise negation) operator yields the bitwise complement of the operand. In the binary representation of the result, every bit has the opposite value of the same bit in the binary representation of the operand. The operand must have an integral type.

What does << mean in C?

<< is the left shift operator. It is shifting the number 1 to the left 0 bits, which is equivalent to the number 1 .

What is bitwise XOR operator in C?

The ^ (bitwise XOR) in C or C++ takes two numbers as operands and does XOR on every bit of two numbers. The result of XOR is 1 if the two bits are different. The << (left shift) in C or C++ takes two numbers, left shifts the bits of the first operand, the second operand decides the number of places to shift.


1 Answers

First of all, the C++ standard itself barely says about padding bits. Essentially all discussion of padding bits comes from the base document (i.e., the C standard).

So the real question is what the C standard says about things. Its footnote 54 gives a fairly concise summary of padding bits in general:

Some combinations of padding bits might generate trap representations, for example, if one padding bit is a parity bit. Regardless, no arithmetic operation on valid values can generate a trap representation other than as part of an exceptional condition such as an overflow. All other combinations of padding bits are alternative object representations of the value specified by the value bits.

Operators might change a padding big. The obvious case would be a padding bit that represented parity. If you change a value's parity, the parity bit would change to match.

The "alternative object representations of the value" part basically mean that as long as you stay "in bounds", the padding bits don't affect your results. For example, if you compare two values, only the representation bits are used to determine the results (6.2.6.1/4):

Two values (other than NaNs) with the same object representation compare equal, but values that compare equal may have different object representations.

The times and places you have to be careful mostly involve undefined or implementation defined behavior. For example, if you store a value into one value in a union, then retrieve a different value in the union, it's possible the second could have the padding bits set to a trap representation, so even looking at the value that way could crash your program (or whatever).

Likewise, if you were to take two values, memcpy each to an buffer of unsigned char, some bits of those bytes might compare as not-equal, even if the values they represented did compare equal.

One place this can bit you even if you never use mempy directly is with some of the compare-and-exchange operators. These use memcpy and memcmp for the underlying operations, so they're also subject to comparing not equal, even though the values being represented are equal:

[atomics.types.operations]/23:

The memcpy and memcmp semantics of the compare-and-exchange operations may result in failed comparisons for values that compare equal with operator== if the underlying type has padding bits, trap bits, or alternate representations of the same value. Thus, compare_exchange_strong should be used with extreme care. On the other hand, compare_exchange_weak should converge rapidly.

Side note: the two large quotes are descriptive, not normative--from a normative viewpoint, padding bits have almost no meaning; almost anything that could expose padding bits or their values involves implementation defined or undefined behavior. The only normative quote here is the one that basically says: "padding bits have no effect."

like image 77
Jerry Coffin Avatar answered Sep 21 '22 11:09

Jerry Coffin