跳到主要内容
版本:master

FFI 说明块

语法

  • EMBED_FFI_BEGIN FFI声明项1+ EMBED_FFI_END

注释:

  1. FFI 声明项支持如下形式:

    形式语法
    1FFI结构体或共用体说明2
    2typedef FFI类型3 标识符
  2. FFI结构体或共用体说明的语法:

    • struct | union 标识符? { 字段声明4* }
  3. FFI类型的语法:

    • int | float
    • FFI结构体或共用体说明
    • (struct | union)? 标识符
    • const FFI类型
    • unsigned FFI类型
    • FFI类型 *
  4. 字段声明的语法:

    • FFI类型 标识符 ([ 整数字面量 ])? ;

描述

FFI 说明块用于在 GS 代码中嵌入结构体、共用体的声明,这些结构体、共用体的内存布局与 C 语言的默认布局保持一致,可以 被用于与 C 语言的互操作;常见于与 ffigsbind 对接交互的中间脚本中。

FFI 提供的基本类型

FFI 提供以下类型作为内置的基础类型可供使用:

  • bool
  • char
  • uchar
  • int8_t
  • uint8_t
  • int16_t
  • uint16_t
  • short
  • int
  • uint
  • int32_t
  • uint32_t
  • long
  • ulong
  • int64_t
  • uint64_t
  • size_t
  • intptr_t
  • float
  • double
  • void

需要注意,在 FFI 说明块中,intfloat 对应的是 32 位的整数和单精度浮点数,这与 GS 语言中的 intfloat 类型不同。

声明的结构体,共用体和 raw_pointer 类型

在 GS 中,结构体或共用体的实例属于 raw_pointer 类型,实例所使用的内存空间由 GC 管理。

当声明了结构体或共用体时,GS 会为每一个声明的结构体/共用体类型生成基本的类型拓展方法:

方法名说明
create创建一个结构体/共用体实例,允许传入额外的参数,按顺序为字段提供值
dup(平凡地)复制一个结构体/共用体实例
to_array将结构体/共用体实例的字段值转换为数组
to_map将结构体/共用体实例的字段值转换为映射
from_array从数组中读取并将值赋值给对应字段
from_map从映射中读取并将值赋值给对应字段
length获取结构体占用的内存空间

to_array, to_map, from_array, from_map 方法只考虑最外层的结构体成员,不递归处理嵌套的结构体字段。这些 方法不适用于共用体,因为共用体的字段是重叠存储的,可能得到意外的结果。

GS 提供了 create 函数的语法糖,以下两种写法等价:

StructType(..) 等价于 StructType.create(..)

示例

EMBED_FFI_BEGIN
// 定义一个结构体类型 Point
struct Point {
float x;
float y;
};

struct DupExample1 {
Point p;
};

struct DupExample2 {
Point* p;
};


// 定义一个共用体类型 Data
union Data {
int i;
float f;
char str[20];
};

EMBED_FFI_END

Point p = Point(1.0, -1.0); // 使用 create 方法创建实例,等同于 Point.create(1.0, -1.0)
writeln(p.x, ", ", p.y); // 输出: 1.0, -1.0

Data d = Data();
d.i = 42;
writeln(d.i); // 输出: 42
d.f = 3.14;
writeln(d.f); // 输出: 3.14
d.str = "Hello, FFI!";
writeln(d.str); // 输出: Hello, FFI!
printlnf("%c", d.str[1]); // 输出: e
writeln(d.i); // (可能的)输出: 1819043144

// 复制结构体实例
DupExample1 de1 = DupExample1();
de1.p.x = 2.0;
de1.p.y = 3.0;

DupExample1 de1_copy = de1.dup();
writeln(de1_copy.p.x, ", ", de1_copy.p.y); // 输出: 2.0, 3.0

de1_copy.p.x = 10.0;
writeln(de1.p.x, ", ", de1.p.y); // 输出: 2.0, 3.0,原实例未被修改

DupExample2 de2 = DupExample2();
de2.p = Point(4.0, 5.0);

DupExample2 de2_copy = de2.dup();
writeln(de2_copy.p.x, ", ", de2_copy.p.y); // 输出: 4.0, 5.0

de2_copy.p.x = 20.0;
writeln(de2.p.x, ", ", de2.p.y); // 输出: 20.0, 5.0,原实例被修改,因为指针字段指向同一内存

// 使用 from_array 和 to_array
Point p2 = Point();
p2.from_array([6.0, 7.0]);
writeln(p2.x, ", ", p2.y); // 输出: 6.0, 7.0

array arr = p2.to_array();
writeln(arr); // 输出: [6.0, 7.0]

// 使用 from_map 和 to_map
Point p3 = Point();
p3.from_map({"x": 8.0, "y": 9.0});
writeln(p3.x, ", ", p3.y); // 输出: 8.0, 9.0

map m = p3.to_map();
writeln(m); // 输出: {"x": 8.0, "y": 9.0}