[Challenge/Puzzle] Implement reinterpret_cast
-
Hey coders, I came up with a little puzzle/challenge for C++, so for those interested, my challenge to you is this: Using any C++ constructs, other than any of the casting constructs*, reimplement the following code:
int i = someIntValue();
int *pint = reinterpret_cast(i)Or in words, find a way to reinterpret_cast an integer into a pointer without casting (implicitly, or explicitly!). You may assume that
sizeof(int)==sizeof(int*)
. I hope to be surprised by answers I hadn't thought of :) * with casting constructs, I mean any form of implicit casts (e.g. int to long int), C-style casts (e.g.(int*)i
) and C++-style casts (e.g. reinterpet_cast(i)
); and also any functions/macro's/API calls (such as STL implementations) which rely internally on casts. Best Regards, Richard -
Hey coders, I came up with a little puzzle/challenge for C++, so for those interested, my challenge to you is this: Using any C++ constructs, other than any of the casting constructs*, reimplement the following code:
int i = someIntValue();
int *pint = reinterpret_cast(i)Or in words, find a way to reinterpret_cast an integer into a pointer without casting (implicitly, or explicitly!). You may assume that
sizeof(int)==sizeof(int*)
. I hope to be surprised by answers I hadn't thought of :) * with casting constructs, I mean any form of implicit casts (e.g. int to long int), C-style casts (e.g.(int*)i
) and C++-style casts (e.g. reinterpet_cast(i)
); and also any functions/macro's/API calls (such as STL implementations) which rely internally on casts. Best Regards, Richard -
This forum is for serious questions, the Lounge is the place for quizzes.
Use the best guess
Hmmm :rolleyes: Didn't realise that. I felt it was more in place in a C++ specific message board than in a lounge, as I do find such challenges to be stimulating myself.
-
This forum is for serious questions, the Lounge is the place for quizzes.
Use the best guess
Richard MacCutchan wrote:
This forum is for serious questions, the Lounge is the place for quizzes.
I deem this is technically appropriate (by the definitions of the rules), it is C++/C code. Where in the rules up at the very top posted by Admin Chris Maunder, does it directly say that is for serious questions. Keep in mind a quiz is a question, you are giving an answer. EDIT:
Chris Maunder wrote:
Please do not post links to your question in one forum from another, unrelated forum (such as the lounge). It will be deleted.
And you said...
Richard MacCutchan wrote:
the Lounge is the place for quizzes.
Trying to guide him in the wrong path ;) , consider re-reading the rules.
Simple Thanks and Regards, Brandon T. H. Programming in C and C++ now, now developing applications, services and drivers (and maybe some kernel modules...psst kernel-mode drivers...psst). Many of life's failures are people who did not realize how close they were to success when they gave up. - Thomas Edison
-
Richard MacCutchan wrote:
This forum is for serious questions, the Lounge is the place for quizzes.
I deem this is technically appropriate (by the definitions of the rules), it is C++/C code. Where in the rules up at the very top posted by Admin Chris Maunder, does it directly say that is for serious questions. Keep in mind a quiz is a question, you are giving an answer. EDIT:
Chris Maunder wrote:
Please do not post links to your question in one forum from another, unrelated forum (such as the lounge). It will be deleted.
And you said...
Richard MacCutchan wrote:
the Lounge is the place for quizzes.
Trying to guide him in the wrong path ;) , consider re-reading the rules.
Simple Thanks and Regards, Brandon T. H. Programming in C and C++ now, now developing applications, services and drivers (and maybe some kernel modules...psst kernel-mode drivers...psst). Many of life's failures are people who did not realize how close they were to success when they gave up. - Thomas Edison
Brandon-X12000 wrote:
I deem this is technically appropriate
I suspect you are in a minority.
Brandon-X12000 wrote:
Trying to guide him in the wrong path
Not at all, the Lounge is the place for such questions; even Chris posts them there.
Use the best guess
-
Hey coders, I came up with a little puzzle/challenge for C++, so for those interested, my challenge to you is this: Using any C++ constructs, other than any of the casting constructs*, reimplement the following code:
int i = someIntValue();
int *pint = reinterpret_cast(i)Or in words, find a way to reinterpret_cast an integer into a pointer without casting (implicitly, or explicitly!). You may assume that
sizeof(int)==sizeof(int*)
. I hope to be surprised by answers I hadn't thought of :) * with casting constructs, I mean any form of implicit casts (e.g. int to long int), C-style casts (e.g.(int*)i
) and C++-style casts (e.g. reinterpet_cast(i)
); and also any functions/macro's/API calls (such as STL implementations) which rely internally on casts. Best Regards, RichardYou could do something like:-
int i = 42;
int* pint = 0;
int** ppint = 0;
ppint += &i;
pint = *ppint;If I'm not mistaken
pint
is now an int pointer to address 42 and no casting as such has taken place."The secret of happiness is freedom, and the secret of freedom, courage." Thucydides (B.C. 460-400)
-
Hey coders, I came up with a little puzzle/challenge for C++, so for those interested, my challenge to you is this: Using any C++ constructs, other than any of the casting constructs*, reimplement the following code:
int i = someIntValue();
int *pint = reinterpret_cast(i)Or in words, find a way to reinterpret_cast an integer into a pointer without casting (implicitly, or explicitly!). You may assume that
sizeof(int)==sizeof(int*)
. I hope to be surprised by answers I hadn't thought of :) * with casting constructs, I mean any form of implicit casts (e.g. int to long int), C-style casts (e.g.(int*)i
) and C++-style casts (e.g. reinterpet_cast(i)
); and also any functions/macro's/API calls (such as STL implementations) which rely internally on casts. Best Regards, Richardint i = someIntValue();
int *pint = 0;
pint += i;Note that this doesn't even require
sizeof(int)==sizeof(int*)
, asi
will be cast to the correct size implicitely. -
int i = someIntValue();
int *pint = 0;
pint += i;Note that this doesn't even require
sizeof(int)==sizeof(int*)
, asi
will be cast to the correct size implicitely. -
But it will also be multiplied by sizeof(int) implicitly.. And if you divide by sizeof(int) first, it kills the lowest bit(s).
Ah, you're right on both accounts. Not that it would make much sense to have an incorrectly aligned pointer, but then the challenge didn't make much sense for practical use anyway...
-
You could do something like:-
int i = 42;
int* pint = 0;
int** ppint = 0;
ppint += &i;
pint = *ppint;If I'm not mistaken
pint
is now an int pointer to address 42 and no casting as such has taken place."The secret of happiness is freedom, and the secret of freedom, courage." Thucydides (B.C. 460-400)
Matthew Faithfull wrote:
ppint += &i;
Doesn't work - you only can add integral types (
size_t
and anything that implicitely converts tosize_t
) to a pointer. Also, as Harold Aptroot pointed out in response to my variant, even if it would work as intended,pint
would point to42*sizeof(int)
, not42
. -
Matthew Faithfull wrote:
ppint += &i;
Doesn't work - you only can add integral types (
size_t
and anything that implicitely converts tosize_t
) to a pointer. Also, as Harold Aptroot pointed out in response to my variant, even if it would work as intended,pint
would point to42*sizeof(int)
, not42
.I haven't tried it as it's, as you point out, not of practical use but &i is certainly integral. Another step may be needed to get around restrictions on adding pointers to pointers but the principle is the same. The multiplication by sizeof(int) is not an really issue as this can be overcome without any casting. The addition was a syntactic nicety to explain what I was doing anyway and is not strictly necessary. How about:-
int i = 42;
int** ppint = &i;
int* pint = *ppint;which is shorter and doesn't do pointer arithmetic.
"The secret of happiness is freedom, and the secret of freedom, courage." Thucydides (B.C. 460-400)
-
Hey coders, I came up with a little puzzle/challenge for C++, so for those interested, my challenge to you is this: Using any C++ constructs, other than any of the casting constructs*, reimplement the following code:
int i = someIntValue();
int *pint = reinterpret_cast(i)Or in words, find a way to reinterpret_cast an integer into a pointer without casting (implicitly, or explicitly!). You may assume that
sizeof(int)==sizeof(int*)
. I hope to be surprised by answers I hadn't thought of :) * with casting constructs, I mean any form of implicit casts (e.g. int to long int), C-style casts (e.g.(int*)i
) and C++-style casts (e.g. reinterpet_cast(i)
); and also any functions/macro's/API calls (such as STL implementations) which rely internally on casts. Best Regards, RichardThe following code compiles and it does return the correct values:
int* f1(int i) { return 0; }
int* f2(int* pi) { return pi; }
union UPointers {
int*(*ag1[2])(int i);
struct SPointers {
int*(*g1)(int i);
int*(*g2)(int* pi);
} my_spointers;
} my_pointers;
int* foo(int i) {
int* (*h1)(int i);
my_pointers.my_spointers.g1 = &f1;
my_pointers.my_spointers.g2 = &f2;
h1 = my_pointers.ag1[1];
return h1(i);
}
int _tmain(int argc, _TCHAR* argv[])
{
for (int i = 12; i < 15; ++i) {
int* pi = foo(i);
std::cout << i << ' ' << pi << std::endl;
}
return 0;
}The output is:
12 0000000C
13 0000000D
14 0000000EThe idea is to abuse a function pointer that is supposed to pass an
int
argument by assigning it to a function that expects anint*
. I'm almost sure there is no implicit conversion involved, but I'm not too familiar with function pointers to be sure. The 'conversion' happens when the function call writes theint
argument to the stack, but the function that is called interprets it as a int*. -
I haven't tried it as it's, as you point out, not of practical use but &i is certainly integral. Another step may be needed to get around restrictions on adding pointers to pointers but the principle is the same. The multiplication by sizeof(int) is not an really issue as this can be overcome without any casting. The addition was a syntactic nicety to explain what I was doing anyway and is not strictly necessary. How about:-
int i = 42;
int** ppint = &i;
int* pint = *ppint;which is shorter and doesn't do pointer arithmetic.
"The secret of happiness is freedom, and the secret of freedom, courage." Thucydides (B.C. 460-400)
Dear Matthew, Thanks for submitting your solution. Unfortunately, ppint is of type int**, whereas &i returns an int*, so this will not work without casting int* to int**.
-
Dear Matthew, Thanks for submitting your solution. Unfortunately, ppint is of type int**, whereas &i returns an int*, so this will not work without casting int* to int**.
I would like to see the assmebler generated for the cast from int* to int**. My expectation is that it would consist of 0 instructions or at most a nop. If no actual cast takes place and none is specified in the code then I say the challenge is met. Assignment from int* to int** is certainly valid. In reality at the backend of most compilers I suspect int* and int** will be same thing anyway. :)
"The secret of happiness is freedom, and the secret of freedom, courage." Thucydides (B.C. 460-400)
-
The following code compiles and it does return the correct values:
int* f1(int i) { return 0; }
int* f2(int* pi) { return pi; }
union UPointers {
int*(*ag1[2])(int i);
struct SPointers {
int*(*g1)(int i);
int*(*g2)(int* pi);
} my_spointers;
} my_pointers;
int* foo(int i) {
int* (*h1)(int i);
my_pointers.my_spointers.g1 = &f1;
my_pointers.my_spointers.g2 = &f2;
h1 = my_pointers.ag1[1];
return h1(i);
}
int _tmain(int argc, _TCHAR* argv[])
{
for (int i = 12; i < 15; ++i) {
int* pi = foo(i);
std::cout << i << ' ' << pi << std::endl;
}
return 0;
}The output is:
12 0000000C
13 0000000D
14 0000000EThe idea is to abuse a function pointer that is supposed to pass an
int
argument by assigning it to a function that expects anint*
. I'm almost sure there is no implicit conversion involved, but I'm not too familiar with function pointers to be sure. The 'conversion' happens when the function call writes theint
argument to the stack, but the function that is called interprets it as a int*.Dear Stefan, I do indeed think (if I am not mistaken) that your code gets the job done without performing any casts. I also enjoyed seeing you use a union for the job. The solution I had in mind also employs unions, but does not use function pointers:
int* withoutCasts(int i)
{
union {int j; int* pint;} converter;
converter.j = i;
return converter.pint;
}Thanks to everyone who spent time thinking on this, and if anyone has a different solution (possibly one without unions) then I'd love to hear it.
-
I would like to see the assmebler generated for the cast from int* to int**. My expectation is that it would consist of 0 instructions or at most a nop. If no actual cast takes place and none is specified in the code then I say the challenge is met. Assignment from int* to int** is certainly valid. In reality at the backend of most compilers I suspect int* and int** will be same thing anyway. :)
"The secret of happiness is freedom, and the secret of freedom, courage." Thucydides (B.C. 460-400)
It's true that in many implementations of C/C++ a pointer to one type is technically (in terms of generated code and storage needs) the same as a pointer to any other type. But in terms of the language, int* is certainly not an int**. At the very least, the compiler will give you an error on the line
int **ppi = &i
, saying there is no conversion from int* to int**. But ok, that's the compiler, so maybe it's just being annoying? One nice way, I think, of realising these two (int* and int**) are two very different objects is the following:int* pi = ...;
int** ppi = ...;
*pi; *ppi; // These two are both valid C++ and we know what this means
**ppi; // This is also valid, but the following:
**pi; // Is not valid, and it is not clear what it's suppose to mean; *pi gives an integer value, so what is the dereference of an integer?So I'd say that int* and int** can't be the same thing, because the one can do something the other can't ;)
-
Dear Stefan, I do indeed think (if I am not mistaken) that your code gets the job done without performing any casts. I also enjoyed seeing you use a union for the job. The solution I had in mind also employs unions, but does not use function pointers:
int* withoutCasts(int i)
{
union {int j; int* pint;} converter;
converter.j = i;
return converter.pint;
}Thanks to everyone who spent time thinking on this, and if anyone has a different solution (possibly one without unions) then I'd love to hear it.
Originally my idea was to use a struct of function pointers and 'iterate' over them to arrive at a different pointer. However, I found that pointer arithmetic apparently doesn't work on function pointers. :( That is when I thought of union. It was only later that I realized the union construct can solve the task by itself. But since I already posted my solution, there was no point in 'watering it down'. ;) Another thing I thought of is overloading virtual functions with different return types. But it would require at least a downcast of the instance pointer:
class base {
public:
virtual ~base() {}
virtual int* foo(int i) { return &i; }
};
class derived : public base {
public:
virtual ~derived() {}
virtual int foo(int i) { return i; } // overrides base::foo()
};
int* bar(int i) {
base* caster = new derived; // implicit downcast here
int* pi = caster->foo(i); // this is the actual 'reinterpret cast'
delete caster;
return pi:
}I wonder if I could get this to work if I put part of the code inside a constructor, before the construction of the vtable - but then the behaviour would be undefined :doh: