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?

legends2k
  • 31,634
  • 25
  • 118
  • 222
  • 3
    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 --> LSB – Prismatic Apr 07 '15 at 03:39
  • @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](http://en.wikipedia.org/wiki/Endianness), if you are unsure of endianness. – legends2k Apr 07 '15 at 06:26
  • 2
    The index of the bitset is different from any consideration of endianness. Index zero is the LSB. Endianess has nothing to do with this. – Prismatic Apr 07 '15 at 06:41
  • 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? – legends2k Apr 07 '15 at 06:45

2 Answers2

17

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.

Pradhan
  • 16,391
  • 3
  • 44
  • 59
  • 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_. – legends2k Apr 07 '15 at 11:31
9

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.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622