FFI 说明块
语法
- EMBED_FFI_BEGIN FFI声明项1+ EMBED_FFI_END
注释:
-
FFI 声明项支持如下形式:
形式 语法 1 FFI结构体或共用体说明2 2 typedef FFI类型3 标识符 -
FFI结构体或共用体说明的语法:
- struct | union 标识符? { 字段声明4* }
-
FFI类型的语法:
- int | float
- FFI结构体或共用体说明
- (struct | union)? 标识符
- const FFI类型
- unsigned FFI类型
- FFI类型 *
-
字段声明的语法:
- FFI类型 标识符 ([ 整数字面量 ])? ;
描述
FFI 说明块用于在 GS 代码中嵌入结构体、共用体的声明,这些结构体、共用体的内存布局与 C 语言的默认布局保持一致,可以
被用于与 C 语言的互操作;常见于与 ffi 和 gsbind 对接交互的中间脚本中。
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 说明块中,int 和 float 对应的是 32 位的整数和单精度浮点数,这与 GS 语言中的 int 和 float 类型不同。
声明的结构体,共用体和 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}