为什么这段代码会编译?

时间:2010-08-27 06:38:29

标签: c++ visual-studio-2008 winapi compilation

昨晚,我太累了,写了这句奇怪的话:

::TerminateThread(::TerminateThread, 0);

令我惊讶的是,编译器没有抱怨(它甚至运行......)

由于TerminateThread()被定义为

BOOL WINAPI TerminateThread(HANDLE hThread, DWORD dwExitCode);

我不知道为什么我能够编译它。

有任何解释吗?

4 个答案:

答案 0 :(得分:7)

HANDLE是指向void的指针,Microsoft的编译器允许隐式地将函数指针转换为指向void的指针。

这使我多次绊倒,尤其是堆函数:

HeapAlloc (GetProcessHeap, 0, size); // oops, should be GetProcessHeap()

答案 1 :(得分:2)

它采用函数::TerminateThread的地址。这是

类型
BOOL WINAPI (*)(HANDLE, DWORD).

HANDLE被定义为

  

typedef PVOID HANDLE;

因此,编译器编写代码将'函数指针'类型转换为PVOID,这在C ++中完全有效($ 4.10 / 2)

  

“rvalue of type”指向cv T的指针,“   其中T是对象类型,可以   转换为类型的右值   “指向cv void的指针。”结果   将“指向cv T的指针”转换为a   “指向cv void的指针”指向   开始存储位置在哪里   类型T的对象就好了   该对象是一个派生程度最高的对象   (1.8)T型(即不是基础   class subobject)。“

编辑2:

@dreamlax是正确的。似乎C ++ 03标准允许将函数指针转换为void *,如下面的程序所示

void f(){}

int main(){
   void (*p)(void) = f;
   void *p1 = p;
}

我想知道为什么。

答案 2 :(得分:1)

真正的答案是:你很幸运。您可以将三种类型的代码提供给C或C ++编译器:

  • 正确的代码,其行为由标准或编译器定义
  • 完全错误的代码将会被错误拒绝
  • 代码,该代码不够正确,无法定义行为,但不足以被拒绝。

最后一类是“未定义的行为”,是关于C和C ++最糟糕的事情之一。编译器将接受代码,但很可能不会执行您想要的操作。将函数指针转换为void指针不是您想要的,并且您可能希望编译器警告您告诉您错误。

以下是possible undefined behaviour in C++.的列表。您可以做的最好的事情是尝试调高编译器的警告级别。在Visual C ++中使用/w3/w4来提高警告级别,它将在编译时捕获更多未定义的行为。在gcc中,使用-ansi -pedantic -W -Wall将警告级别调高为完整。

答案 3 :(得分:0)

我猜HANDLE被定义为void*,因此任何指针(甚至函数指针)都可以隐式地转换为HANDLE