# 04 - 函数定义与调用 Viper 的函数定义使用 Python 的 `def` 语法,通过类型注解指定参数类型和返回类型。 ## 基本函数定义 ```python def add(a: t.CInt, b: t.CInt) -> t.CInt: return a + b ``` 等价 C 代码: ```c int add(int a, int b) { return a + b; } ``` ## 无返回值函数 ```python def print_msg(msg: t.CConst | t.CChar | t.CPtr) -> t.CVoid: serial.puts(msg) ``` 等价 C 代码: ```c void print_msg(const char* msg) { serial_puts(msg); } ``` ## 函数修饰符 通过返回类型的 `|` 组合添加函数修饰符: ### 导出函数 ` t.CExport` 控制函数的符号可见性——标记为 `t.CExport` 的函数不加 SHA1 前缀,全局可见。详见 [01-overview.md 中 t.CExport 深度解析](01-overview.md#tcexport-深度解析)。 ```python def _start() -> t.CInt | t.CExport: return 0 ``` ### 外部函数声明 使用 `c.State` 表示仅声明不定义: ```python def isr0() -> t.CExtern | t.CVoid | c.State: pass def isr1() -> t.CExtern | t.CVoid | c.State: pass ``` 等价 C 代码: ```c extern void isr0(); extern void isr1(); ``` ### 内联函数 `t.CInline` 标记函数为内联函数,编译器在调用点直接展开函数体。详见 [01-overview.md 中 t.CInline 深度解析](01-overview.md#tcinline-深度解析)。 ```python 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 函数](01-overview.md#tcdefine-函数)。 ```python def MAKE_FLAG(bit) -> t.CDefine: return (1 << bit) ``` ### 静态函数 ```python def helper() -> t.CVoid | t.CStatic: pass ``` ## 函数属性装饰器 使用 `@c.Attribute` 添加 GCC `__attribute__` 属性: ```python @c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16)) def _start() -> t.CInt: return 0 ``` 等价 C 代码: ```c __attribute__((section(".text.startup"), aligned(16))) int _start() { return 0; } ``` ### 常用属性组合 ```python @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 属性: ```python def foo() -> t.CInt | t.attr.llvm.nobuiltin | t.attr.llvm.nounwind: return 0 ``` ## 多返回值(CReturn) 使用 `@c.CReturn` 装饰器实现多返回值,通过指针参数实现: ```python @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.CInt` → `t.CInt | t.CPtr`) 3. 参数名自动生成为 `__ReturnValue0__`、`__ReturnValue1__` 等 4. 调用处自动传参 `&xxx` 5. 必须使用左右值赋值,返回值不能直接传入函数。 ## 指针参数 ```python def read_data(buf: t.CChar | t.CPtr, size: t.CSizeT) -> t.CInt: pass ``` 等价 C 代码: ```c int read_data(char* buf, size_t size); ``` ### 输出参数模式 使用 `c.Addr` 传递变量地址作为输出参数: ```python res: t.CInt = fat32.opendir("/", c.Addr(dp)) ``` 等价 C 代码: ```c int res = fat32_opendir("/", &dp); ``` 后续会使用隐式左值获取来减少 `c.Addr` 的直接使用。 ## 函数指针类型 使用 `t.Callable` 定义函数指针类型: ```python irq_handler_t: t.CTypedef | t.Callable[[], t.CInt] ``` 等价 C 代码: ```c typedef int (*irq_handler_t)(); ``` 带参数的函数指针: ```python callback_t: t.Callable[[t.CInt, t.CInt], t.CVoid] ``` ## 默认参数 Viper 支持函数默认参数值: ```python def create_window(x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, title: t.CConst | str = "Window") -> t.CInt: pass ``` ## return 语句 ```python return 0 # return 0; return # return; (void 函数) return a, b # 多返回值(需配合 @c.CReturn) ``` ## 全局变量声明 函数外的变量声明为全局变量,函数内通过 `global` 关键字访问: ```python BootInfo: bootinfo | t.CPtr def init() -> t.CVoid: global BootInfo BootInfo = saved_rdi ``` 支持 func-in-func 嵌套函数。 ## Call Func 函数调用 函数调用最好通过顺序调用来实现 ```python 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 中的标准实现方法,但实际上,你也可以乱序传参。 ```python # 仍然用刚才的 add 举例 def main() -> int | t.CExport: print(add(z=3, x=1, y=2)) # (1 + 2) * 3 = 9 ``` 乱序传参或带参传参对于结构体的初始化同样有效。同时,你也能够给函数指定默认值。 ```python 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 ``` 在结构体中也可以指定默认值。