Why does std::bitset expose bits in little-endian fashion?
Asked Answered
P

2

10

When I use std::bitset<N>::bitset( unsigned long long ) this constructs a bitset and when I access it via the operator[], the bits seems to be ordered in the little-endian fashion. Example:

std::bitset<4> b(3ULL);
std::cout << b[0] << b[1] << b[2] << b[3];

prints 1100 instead of 0011 i.e. the ending (or LSB) is at the little (lower) address, index 0.

Looking up the standard, it says

initializing the first M bit positions to the corresponding bit values in val

Programmers naturally think of binary digits from LSB to MSB (right to left). So the first M bit positions is understandably LSB → MSB, so bit 0 would be at b[0].

However, under shifting, the definition goes

The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are zero-filled.

Here one has to interpret the bits in E1 as going from MSB → LSB and then left-shift E2 times. Had it been written from LSB → MSB, then only right-shifting E2 times would give the same result.

I'm surprised that everywhere else in C++, the language seems to project the natural (English; left-to-right) writing order (when doing bitwise operations like shifting, etc.). Why be different here?

Pend answered 7/4, 2015 at 3:16 Comment(4)
b[0] prints the LSB. I don't see how you're getting 'little endian' from this. When you print as a string, you get an output of MSB --> LSBMuzzle
@Pris little-endian means the ending digit is at the little address (lower index, 0), Arabic number system is in big endian i.e. ending (LSB) is at a higher address (index goes from left to right) so it's big, while here it's little. Please read this, if you are unsure of endianness.Pend
The index of the bitset is different from any consideration of endianness. Index zero is the LSB. Endianess has nothing to do with this.Muzzle
Please do understand that I used the word little-endian just to give this ordering the name, I very well know that the standard has no notion of endianness. Reading the question shows that, all I'm asking is why does that quote from the standard get interpreted by implementations as little, why not project it as big?Pend
O
18

There is no notion of endian-ness as far as the standard is concerned. When it comes to std::bitset, [template.bitset]/3 defines bit position:

When converting between an object of class bitset<N> and a value of some integral type, bit position pos corresponds to the bit value 1<<pos. The integral value corresponding to two or more bits is the sum of their bit values.

Using this definition of bit position in your standard quote

initializing the first M bit positions to the corresponding bit values in val

a val with binary representation 11 leads to a bitset<N> b with b[0] = 1, b[1] = 1 and remaining bits set to 0.

Orientalize answered 7/4, 2015 at 3:40 Comment(1)
Exactly what I wanted, thanks! My confusion stems from thinking about how bit-shifting operator is defined: The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are zero-filled. To make sense out of it, E1 should be imagined (MSB -> LSB) big-endian (otherwise it'd mean right shift to get the same effect). I thought the standard implies big-endian here, while in bitset it seems to go little-endian. However, the standard then clarifies: the value of the result is E1 × 2^E2, reduced modulo one more than the maximum value representable in the result type.Pend
H
10

This is consistent with the way bits are usually numbered - bit 0 represents 20, bit 1 represents 21, etc. It has nothing to do with the endianness of the architecture, which concerns byte ordering not bit ordering.

Heintz answered 7/4, 2015 at 3:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.