Tricky interview question for mid-level C++ developer

I was asked this question on the interview, and I can't really understand what is going on here. The question is "What would be displayed in the console?"

#include <iostream>

int main()
{
    unsigned long long n = 0;
    ((char*)&n)[sizeof(unsigned long long)-1] = 0xFF;

    n >>= 7*8;

    std::cout << n;
}

What is happening here, step by step?


Solution 1:

Let's get this one step at a time:

((char*)&n)

This casts the address of the variable n from unsigned long long* to char*. This is legal and actually accessing objects of different types via pointer of char is one of the very few "type punning" cases accepted by the language. This in effect allows you to access the memory of the object n as an array of bytes (aka char in C++)

((char*)&n)[sizeof(unsigned long long)-1]

You access the last byte of the object n. Remember sizeof returns the dimension of a data type in bytes (in C++ char has an alter ego of byte)

((char*)&n)[sizeof(unsigned long long)-1] = 0xFF;

You set the last byte of n to the value 0xFF.

Since n was 0 initially the layout memory of n is now:

00  .. 00 FF

Now notice the ... I put in the middle. That's not because I am lazy to copy paste the values the amount of bytes n has, it's because the size of unsigned long long is not set by the standard to a fixed dimension. There are some restrictions, but it can vary from implementation to implementation. So this is the first "unknown". However on most modern architectures sizeof (unsigned long long) is 8, so we are going to go with this, but in a serious interview you are expected to mention this.

The other "unknown" is how these bytes are interpreted. Unsigned integers are simply encoded in binary. But it can be little endian or big endian. x86 is little endian so we are going with it for the exemplification. And again, in a serious interview you are expected to mention this.

n >>= 7*8;

This right shifts the value of n 56 times. Pay attention, now we are talking about the value of n, not the bytes in memory. With our assumptions (size 8, little endian) the value encoded in memory is 0xFF000000 00000000 so shifting it 7*8 times will result in the value 0xFF which is 255.

So, assuming sizeof(unsigned long long) is 8 and a little endian encoding the program prints 255 to the console.


If we are talking about a big endian system, the memory layout after setting the last byte to 0xff is still the same: 00 ... 00 FF, but now the value encoded is 0xFF. So the result of n >>= 7*8; would be 0. In a big endian system the program would print 0 to the console.


As pointed out in the comments, there are other assumptions:

  • char being 8 bits. Although sizeof(char) is guaranteed to be 1, it doesn't have to have 8 bits. All modern systems I know of have bits grouped in 8-bit bytes.

  • integers don't have to be little or big endian. There can be other arrangement patterns like middle endian. Being something other than little or big endian is considered esoteric nowadays.

Solution 2:

Cast the address of n to a pointer to chars, set the 7th (assuming sizeof(long long)==8) char element to 0xff, then right-shift the result (as a long long) by 56 bits.