Прошлой ночью, будучи слишком тир ed, я написал эту странную строку:
::TerminateThread(::TerminateThread, 0);
К моему удивлению, компилятор не жалуется (он даже запускается ...)
Поскольку TerminateThread () определяется как
BOOL WINAPI TerminateThread(HANDLE hThread, DWORD dwExitCode);
, я не уверен, почему я могу скомпилировать его.
Есть объяснения?
HANDLE
— это указатель на void, а компилятор Microsoft позволяет неявно преобразовывать указатель на функцию в указатель на void.
Это много раз сбивало меня с толку, особенно с функциями кучи:
HeapAlloc (GetProcessHeap, 0, size); // oops, should be GetProcessHeap()
Принимает адрес функции ::TerminateThread
. Это тип
BOOL WINAPI (*)(HANDLE, DWORD).
HANDLE определяется как
typedef PVOID HANDLE;
Таким образом, компилятор написал код для преобразования типа «указатель функции» в PVOID, который полностью допустим в C++ ($4.10/2)
"rvalue типа "указатель на cv T", где T — тип объекта, может быть преобразуется в rvalue типа «указатель на cv недействителен». Результат преобразование «указателя на cv T» в «указатель на cv void» указывает на начало места хранения, где объект типа T находится, как если бы объект является наиболее производным объектом (1.8) типа T (т. е. не базового class subobject)."
EDIT 2:
@dreamlax верен. Похоже, что стандарт C++03 не позволяет преобразовывать указатель функции в void *, как показано в приведенной ниже программе
void f(){}
int main(){
void (*p)(void) = f;
void *p1 = p;
}
Интересно, почему.
Я думаю, HANDLE
определяется как void*
, поэтому любой указатель (даже указатель на функцию) может быть неявно приведен к HANDLE
Настоящий ответ: вам повезло. Есть три типа кода, который вы можете передать компилятору C или C++:
Эта последняя категория называется «Неопределенное поведение» и является одной из худших вещей в C и C++. Компилятор примет код, но, скорее всего, не сделает то, что вы хотели. Преобразование указателя функции в указатель void — это не то, что вам нужно, и вы, вероятно, хотите, чтобы компилятор предупреждал вас о том, что вы допустили ошибку.
Вот список возможного неопределенного поведения в C++. Лучшее, что вы можете сделать, это попытаться повысить уровень предупреждения вашего компилятора. В Visual C++ используйте /w3
или /w4
, чтобы повысить уровень предупреждения, и во время компиляции он будет обнаруживать более неопределенное поведение. В gcc используйте -ansi -pedantic -W -Wall
, чтобы поднять уровень предупреждения до полного.