5.8 KiB
04 - 函数定义与调用
Viper 的函数定义使用 Python 的 def 语法,通过类型注解指定参数类型和返回类型。
基本函数定义
def add(a: t.CInt, b: t.CInt) -> t.CInt:
return a + b
等价 C 代码:
int add(int a, int b) {
return a + b;
}
无返回值函数
def print_msg(msg: t.CConst | t.CChar | t.CPtr) -> t.CVoid:
serial.puts(msg)
等价 C 代码:
void print_msg(const char* msg) {
serial_puts(msg);
}
函数修饰符
通过返回类型的 | 组合添加函数修饰符:
导出函数
export 关键字控制函数的符号可见性——标记为 export 的函数不加 SHA1 前缀,裸名导出、全局可见。详见 01-overview.md 中 t.CExport 深度解析。
export def _start() -> t.CInt:
return 0
外部函数声明
使用 extern 关键字表示仅声明不定义:
extern def isr0() -> t.CVoid: pass
extern def isr1() -> t.CVoid: pass
等价 C 代码:
extern void isr0();
extern void isr1();
注明:
t.State/t.CExtern/t.CExport注解旧写法已废弃(t.State仅t.CEnum内部临时使用)。
内联函数
t.CInline 标记函数为内联函数。当前无调用点展开实现,t.CInline 仅作存储类标记;实际内联用 @c.Attribute(t.attr.always_inline())(期望后续支持)。详见 01-overview.md 中 t.CInline 深度解析。
def fast_add(a: t.CInt, b: t.CInt) -> t.CInt | t.CInline:
return a + b
宏函数
宏函数存在两种形式:def f(...) -> t.CDefine,或 define 软关键字 define f(...)(自动追加 t.CDefine 返回注解);存根保留完整函数体;调用点按编译期内联宏展开(TPC 已实现,Test/DefineTest 实证)。详见 01-overview.md 中 t.CDefine 函数。
注明:TransPyV 端目前仅识别返回注解为 i32,调用点展开尚未对齐(期望)。
def MAKE_FLAG(bit) -> t.CDefine:
return (1 << bit)
静态函数
def helper() -> t.CVoid | t.CStatic:
pass
函数属性装饰器
使用 @c.Attribute 添加 GCC __attribute__ 属性:
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16))
def _start() -> t.CInt:
return 0
等价 C 代码:
__attribute__((section(".text.startup"), aligned(16)))
int _start() {
return 0;
}
常用属性组合
@c.Attribute(t.attr.always_inline())
def hot_path() -> t.CInt:
return 0
@c.Attribute(t.attr.noreturn())
def panic(msg: t.CConst | t.CChar | t.CPtr) -> t.CVoid:
serial.puts(msg)
while True: pass
@c.Attribute(t.attr.packed)
LLVM 函数属性
在返回类型注解中通过 t.attr.llvm 指定 LLVM 属性:
def foo() -> t.CInt | t.attr.llvm.nobuiltin | t.attr.llvm.nounwind:
return 0
已支持:always_inline / noinline / noreturn / pure / const / nounwind / noredzone / stackrealign / willreturn / mustprogress;示例中的 nobuiltin 尚未映射(会被静默丢弃,期望支持)。
多返回值(CReturn)
使用 @c.CReturn 装饰器实现多返回值,返回多个值的函数打包为 LLVM struct 返回,调用处用元组解包 a, b = f() 接收:
@c.CReturn(t.CInt, t.CInt)
def divmod(a: t.CInt, b: t.CInt) -> t.CVoid:
q: t.CInt = a // b
r: t.CInt = a % b
return q, r
q, r = divmod(a, b)
规则:
CReturn中的类型数量决定返回值个数- 必须使用左右值(元组解包)赋值,返回值不能直接传入函数。
指针参数
def read_data(buf: t.CChar | t.CPtr, size: t.CSizeT) -> t.CInt:
pass
等价 C 代码:
int read_data(char* buf, size_t size);
输出参数模式
使用 c.Addr 传递变量地址作为输出参数:
res: t.CInt = fat32.opendir("/", c.Addr(dp))
等价 C 代码:
int res = fat32_opendir("/", &dp);
后续会使用隐式左值获取来减少 c.Addr 的直接使用。
函数指针类型
使用 t.Callable 定义函数指针类型:
irq_handler_t: t.CTypedef | t.Callable[[], t.CInt]
等价 C 代码:
typedef int (*irq_handler_t)();
带参数的函数指针:
callback_t: t.Callable[[t.CInt, t.CInt], t.CVoid]
默认参数
Viper 支持函数默认参数值:
def create_window(x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, title: t.CConst | str = "Window") -> t.CInt:
pass
return 语句
return 0 # return 0;
return # return; (void 函数)
return a, b # 多返回值(需配合 @c.CReturn)
全局变量声明
函数外的变量声明为全局变量,函数内通过 global 关键字访问:
BootInfo: bootinfo | t.CPtr
def init() -> t.CVoid:
global BootInfo
BootInfo = saved_rdi
支持 func-in-func 嵌套函数。
Call Func 函数调用
函数调用最好通过顺序调用来实现
def add(x: int, y: int, z: int):
return (x + y) * z
export def main() -> int:
print(add(1, 2, 3)) # (1 + 2) * 3 = 9
这也是 C 中的标准实现方法,但实际上,你也可以乱序传参。
# 仍然用刚才的 add 举例
export def main() -> int:
print(add(z=3, x=1, y=2)) # (1 + 2) * 3 = 9
乱序传参或带参传参对于结构体的初始化同样有效。同时,你也能够给函数指定默认值。
def add(x: int, y: int, z: int = 1):
return (x + y) * z
export def main() -> int:
print(add(1, 2)) # (1 + 2) * 1 = 3
在结构体中也可以指定默认值。