How is the following function pointer assignment:
exit = (void (*)()) &jump;
Different from:
exit = &jump;
where exit is a function pointer defined as:
void (*exit) ();
and 'jump' is a function declared as:
void jump();
exit = (void (*)()) &jump;
The first one uses forced casting. This is dangerous because it can screw up your program without letting you know if the types do not match up, as it will not be caught at compile time.
So if you were to do this:
int func() {return 1;}
auto exit = (void (*)()) &func;
...that would be bad. However, it's better if you do the below:
exit = &jump;
The second one uses compile-time type checking. This is safer because the compiler will check for type at compile-time. This gives you a stronger type guarantee.
The best option is to use static_cast<void(*)()> It's type-safe, and tells the programmer more of your intent of what you were trying to do.
auto exit = static_cast<void(*)()>(&func);
If you have C++, you can try the following things:
If you don't want to concern yourself with type, use auto.
auto exit = &func
This will ensure types will match up.
If you want to examine the type, use typeid().name from <typeinfo> which exists in C++11 and later:
std::cout << typeid(exit).name << std::endl;
While this usually gives some weird output for functions, you may find some information that can help you, the best one being if the two types are different.
Here's a working example showing the issue at run-time with function pointer casting: http://coliru.stacked-crooked.com/a/47f74e8b6f389812
static_cast the first would fail if detected as invalid by the compiler; if applied to the second, it would ensure this and also signal intent by the programmer. C-style casts should be avoided wherever possible. (So should any cast, but C++ provides a much better set.)auto neither signals intent nor prevents the programmer accidentally declaring/assigning the wrong type. Overhead is not the only issue that has to be considered here - as your answer acknowledged.auto case stores a copy, and if jump is not of pointer-to-function or function-type, it could have a cost.They are very similar.
In C, if the functions and types are EXACTLY as described:
void (*exit) ();
void jump();
exit = (void (*)()) &jump;
exit = &jump;
are identical.
Now what happens when I change jump:
int jump();
now we are running undefined behavior, and no errors or warnings occur, if we call exit after:
exit = (void (*)()) &jump;
but here we get a type error:
exit = &jump;
In addition, more subtle differences can occur -- for example jump could get a calling convention, and thus not be able to be stored in exit, and things break.
In C++, there is another subtle difference. If jump is an overloaded function, and exit is not a raw function pointer (but, say, a std::function<void()>), the first could compile while the second might not. Casting a name to a function pointer type can trigger overload resolution, and without it some code fails to work.
You would be safer using static_cast<void(*)()> however.
int through a void (*)() could cause problems. There are some low-level tasks where one has to do things like this.int. Or maybe a caller clean-up, where the called code expects some room to stuff the int, and it isn't planned (as it is supposed to return void). The fact is that most int sized return values show up in registers, usually in registers the function is not supposed to preserve, makes bad behavior unlikely.void function does not return a value, and so use the register normally used for returning ints to hold a value that is not meant to be disturbed by the function callThe two assignments have the same effect. The first way "casts" &jump to a pointer to a function that takes no parameters and returns void, but &jump already is that!
exitand what isjump?