In compiling some interview test questions, I'm currently taking examples from various sources and running through them to gauge their difficulty level and correctness. I've come across one that I think is broken, but it's also possible I'm missing something: if I am, I want to know, not only for my own knowledge but then it would also indicate that this is potentially a good, tricky question. I'd like you to help me regain my sanity and re-affirm the trust I have placed in myself. :D
What is the correct way to cast p at the placeholder "???" in the following code?
#include <iostream> using namespace std; uint16_t hash(void *p) { uint32_t val = ???; return (uint16_t)(val ^ (val >> 16)); } int main(int argc, char *argv[]) { uint32_t a[20]; for(uint32_t i = 0; i < 20; ++i) { a[i] = i; cout << hash(a + i) << endl; } }
Choose one:
static_cast<uint32_t>(p)
dynamic_cast<uint32_t>(p)
reinterpret_cast<uint32_t>(p)
const_cast<uint32_t>(p)
Ignoring for a moment that the call to hash
must be ::hash
to guarantee disambiguity with the standard library (e.g. this line doesn't compile for me in GCC 5.3.0, C++14 mode), I have a problem with the question.
Firstly, it's not clear what the program's supposed to do. Hash the array values, or hash the element locations? Because at the moment the function is receiving pointers-to-elements, but all the available answers assume that those pointers are to be themselves converted to uint32_t
and used as the hash value. If that's the case, then even if you use a reinterpret_cast
then there is a bug because sizeof(void*)
may not be sizeof(uint32_t)
; val
in that function should be intptr_t
instead. The use of uint32_t
for the type of the array elements themselves just confuses matters further if that's effectively a co-incidence.
Or the function is supposed to hash the value and the correct answer is not in the list: *static_cast<uint32_t*>(p)
.
The "correct" answer is apparently reinterpret_cast<uint32_t>(p)
, which makes me think the intention of the program is to hash the array element addresses.
Am I imagining these problems?
Is the question clear and is the solution one of the four choices offered?
What am I? Answer: A mirror.
Answer: The letter “M.”
A die (plural: dice) 🎲 Each side of a cube is called it's "face". There are a total of 6 + 5 + 4 + 3 + 2 + 1 = 21 dots or "eyes" over the 6 surfaces.
Answer: A shadow.
Just to summarize all the points you made in the question and the comments. Basically, the answer to this question is probably:
The correct cast to use is
reinterpret_cast
1†‡.
That's a lot of footnotes! I guess that's what makes it a real C++ question. In any event, I wouldn't ask it in an interview – it's too trick question – and there's plenty of real questions with real, direct answers that you can ask instead.
1 On a 64-bit system, you can't any_kind_of_cast a void*
to a uint32_t
. So they're all wrong.
† There's a name lookup issue in C++11 between the user-provided hash()
and the the class template std::hash<T>
. You should obviously link them to why is using namespace std;
considered bad practice?
‡ Even if the above weren't problems that prevented the code from compiling in the first place, is the intent here to actually hash the pointers into a
and not the values of a
? The most-likely-correct answer should be:
auto val = *static_cast<const uint32_t*>(p);
If it is about hashing pointers, then reinterpret_cast
would be the correct cast but not to uint32_t
(as per (1)). We would want to use uintptr_t
:
auto val = reinterpret_cast<uintptr_t>(p);
In the case of 64-bit, you'd probably want to do something either than val ^ (val >> 16)
, since you're effectively ignoring the upper 32-bits, but at least this would get you to a correct cast that would compile everywhere.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With