Why does this code compile?
Last night, being too tired, I wrote this strange line:
::TerminateThread(::TerminateThread, 0);
To my surprise, the compiler does n开发者_开发问答ot complain (It even run...)
Since TerminateThread() is defined as
BOOL WINAPI TerminateThread(HANDLE hThread, DWORD dwExitCode);
I'm no sure why I am able to compile it.
Any explanation?
HANDLE
is a pointer to void, and Microsoft's compiler allows implicitly converting a function pointer to a pointer to void.
This tripped me up many times, especially with the heap functions:
HeapAlloc (GetProcessHeap, 0, size); // oops, should be GetProcessHeap()
It takes the address of the function ::TerminateThread
. This is of type
BOOL WINAPI (*)(HANDLE, DWORD).
HANDLE is defined as
typedef PVOID HANDLE;
So, the compiler wrote code to convert the 'function pointer' type to PVOID which is perfectly valid in C++ ($4.10/2)
"An rvalue of type “pointer to cv T,” where T is an object type, can be converted to an rvalue of type “pointer to cv void.” The result of converting a “pointer to cv T” to a “pointer to cv void” points to the start of the storage location where the object of type T resides, as if the object is a most derived object (1.8) of type T (that is, not a base class subobject)."
EDIT 2:
@dreamlax is correct. It appears that C++03 standard does not allow converting a function pointer to a void * as the program below shows
void f(){}
int main(){
void (*p)(void) = f;
void *p1 = p;
}
I wonder why.
The real answer is: you got lucky. There are three types of code you can feed to a C or C++ compiler:
- Code which is correct and whose behaviour is defined by the Standard or a compiler
- Code which is totally wrong which will be rejected with an error
- Code which is not correct enough to have defined behaviour, but not wrong enough to be rejected.
This last category is "Undefined behaviour" and is one of the worst things about C and C++. The compiler will accept the code, but it most likely won't do what you wanted. Converting a function pointer to a void pointer is not what you wanted, and you probably want a compiler warning telling you that you made a mistake.
Here's a list of possible undefined behaviour in C++. The best thing you can do is try to turn up the warning level of your compiler. In Visual C++ use /w3
or /w4
to turn the warning level up, and it will catch more undefined behaviour at compile time. In gcc, use -ansi -pedantic -W -Wall
to turn up your warning level to full.
I guess HANDLE
is defined as void*
, so any pointer (even a function pointer) can be casted implicitly to HANDLE
精彩评论