C语言绑定

crystal允许你直接调用现成的C库。此外,crystal还提供了像out, to_unsafe之类的操作,使用绑定是非常便利的。

Lib

lib声明了一组C函数和类型。

  1. @[Link("pcre")]
  2. lib LibPCRE
  3. end

一个lib的名称通常以Lib开头, 但不是强制的。属性用来传递标志给连接器, 用于查找外部库。@[Link("pcre")]将会传递 -lpcre给连接器,但是连接器会优先尝试pkg-config 。@[Link(ldflags: "…")]将会不作修改直接传递这些标志给连接器,如@[Link(ldflags: "-lpcre")]。这里还有一个使用反引号的技巧, 如

@[Link(ldflags: "pkg-config libpcre —libs")]

@[Link(framework: "Cocoa")]将传递 -framework Cocoa 到连接器 (only useful in Mac OS X).

fun

fun用于在lib内部定义一个C绑定函数。

  1. lib C
  2. # In C: double cos(double x)
  3. fun cos(value : Float64) : Float64
  4. end

一旦绑定成功,函数就在C类型内部生效 ,使用就像是调用一个类的方法一样。

  1. C.cos(1.5) #=> 0.0707372

如果函数没有参数 ,可以省略括号。

  1. lib C
  2. fun getch : Int32
  3. end
  4. C.getch

如果函数没有返回 ,则返回类型也可以省略。

  1. lib C
  2. fun srand(seed : UInt32)
  3. end
  4. C.srand(1_u32)

绑定可变参数的函数

  1. lib X
  2. fun variadic(value : Int32, ...) : Int32
  3. end
  4. X.variadic(1, 2, 3, 4)

注意:调用C绑定函数必须要正确声明参数类型。

因为crystal的函数必须用小写开头,所以在使用fun时也必须采用小写 。如果C库中存在大写开头的函数,可以像下面这样写:

  1. lib LibSDL
  2. fun init = SDL_Init(flags : UInt32) : Int32
  3. end

如果名称不是有效的函数或类型,可以使用字符串的形式

  1. lib LLVMIntrinsics
  2. fun ceil_f32 = "llvm.ceil.f32"(value : Float32) : Float32
  3. end

可以用于C绑定的数据类型有: 1. Primitive types (Int8, …, Int64, UInt8, …, UInt64, Float32, Float64)

  • Pointer types (Pointer(Int32), which can also be written as Int32*)

  • Static arrays (StaticArray(Int32, 8), which can also be written as Int32[8])

  • Function types (Function(Int32, Int32), which can also be written as Int32 -> Int32)

  • Other struct, union, enum, type or alias declared previously.

  • Void: the absence of a return value.

  • NoReturn: similar to Void, but the compiler understands that no code can be executed after that invocation.

  • Crystal structs marked with the @[Extern] attribute

标准库定义了LibC作为C类型的别名,比如有像int, short, size_t之类的类型。

  1. lib MyLib
  2. fun my_fun(some_size : LibC::SizeT)
  3. end

注意: C的char在crystal中是UInt8, 所以const char 或char是 UInt8 。The Char type in Crystal is a unicode codepoint so it is represented by four bytes, making it similar to an Int32, not to an UInt8. There's also the alias LibC::Char if in doubt.

//todo