过程类型

过程类型是指向过程的内部指针。过程类型变量允许赋值 nil 。

示例:

  1. proc printItem(x: int) = ...
  2. proc forEach(c: proc (x: int) {.cdecl.}) =
  3. ...
  4. forEach(printItem) # 将不会编译这个,因为调用约定不同
  1. type
  2. OnMouseMove = proc (x, y: int) {.closure.}
  3. proc onMouseMove(mouseX, mouseY: int) =
  4. # 有默认的调用约定
  5. echo "x: ", mouseX, " y: ", mouseY
  6. proc setOnMouseMove(mouseMoveEvent: OnMouseMove) = discard
  7. # 'onMouseMove' 有默认的调用约定,可以兼容 'closure':
  8. setOnMouseMove(onMouseMove)

过程类型的一个底层细节问题是,过程的调用约定会影响类型的兼容性: 过程类型只有在调用约定相同的情况下才兼容。 有个延伸的特例,调用约定为 nimcall 的过程可以被传递给期望调用约定为 closure 的过程参数。

Nim 支持下列 calling conventions “调用约定”:

nimcall

是Nim proc 使用的默认约定。它与 fastcall 相同,但只适用于支持 fastcall 的 C 编译器。

closure

程序类型 没有任意编译指示注解的默认调用约定,该过程有一个隐藏参数( environment “环境”)。

具有 closure 调用约定的过程变体占用两个机器字。一个是过程的指针,另一个是指向隐藏参数环境的指针。

stdcall

这是由微软指定的标准调用惯例,生成的 C 过程将用 __stdcall 关键字声明。

cdecl

其意味着一个过程应使用与 C 编译器相同的约定。在 Windows 中,将用 __cdecl 关键字声明生成的 C 过程。

safecall

这是由微软指定的安全调用约定,将用 __safecall 关键字声明生成的 C 程序。 安全 这个词是指所有的硬件寄存器都应被 push 到硬件堆栈中。

inline

内联约定表示调用者不应该调用过程,而是直接内联其代码。

需注意, Nim 自身并不内联,而是留给 C 编译器,它将生成 __inline 过程,这只是给编译器的提示,编译器则可能忽略,也有可能内联那些没有 inline 的过程。

fastcall

对于不同的 C 编译器其含义不同,有一种是表示 C 语言中的 __fastcall 。

thiscall

这是微软指定的调用约定,应用于 x86 架构上 C++ 类的成员函数。

syscall

其与 C 语言中的 __syscall 相同,用于中断。

noconv

其生成的 C 代码将不会去明确调用约定,将使用 C 编译器自身的默认调用约定。

这是有必要的,因为 Nim 过程的默认调用约定是 fastcall 以提高速度。

大多数调用约定只存在于 32 位 Windows 平台。

默认的调用约定是 nimcall ,除非它是一个内部过程(一个过程中的过程)。对于一个内部过程,将分析它是否访问其环境,如果它访问了环境,就采用 closure 调用约定,否则就采用 nimcall 调用约定。