Files
ViperOS/vpsdk/wiki/04-functions.md
2026-07-19 12:38:20 +08:00

5.2 KiB
Raw Blame History

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);
}

函数修饰符

通过返回类型的 | 组合添加函数修饰符:

导出函数

t.CExport 控制函数的符号可见性——标记为 t.CExport 的函数不加 SHA1 前缀,全局可见。详见 01-overview.md 中 t.CExport 深度解析

def _start() -> t.CInt | t.CExport:
    return 0

外部函数声明

使用 c.State 表示仅声明不定义:

def isr0() -> t.CExtern | t.CVoid | c.State: pass
def isr1() -> t.CExtern | t.CVoid | c.State: pass

等价 C 代码:

extern void isr0();
extern void isr1();

内联函数

t.CInline 标记函数为内联函数,编译器在调用点直接展开函数体。详见 01-overview.md 中 t.CInline 深度解析

def fast_add(a: t.CInt, b: t.CInt) -> t.CInt | t.CInline:
    return a + b

宏函数

当函数返回类型注解包含 t.CDefine 时,该函数被视为宏函数,不生成 LLVM IR 函数定义,在调用处内联展开。详见 01-overview.md 中 t.CDefine 函数

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

多返回值CReturn

使用 @c.CReturn 装饰器实现多返回值,通过指针参数实现:

@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

规则:

  1. CReturn 中的类型数量决定返回值个数
  2. 自动为每个返回类型添加指针参数(t.CIntt.CInt | t.CPtr
  3. 参数名自动生成为 __ReturnValue0____ReturnValue1__
  4. 调用处自动传参 &xxx
  5. 必须使用左右值赋值,返回值不能直接传入函数。

指针参数

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

def main() -> int | t.CExport:
    print(add(1, 2, 3)) # (1 + 2) * 3 = 9

这也是 C 中的标准实现方法,但实际上,你也可以乱序传参。

# 仍然用刚才的 add 举例
def main() -> int | t.CExport:
    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

def main() -> int | t.CExport:
    print(add(1, 2)) # (1 + 2) * 1 = 3

在结构体中也可以指定默认值。