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

255 lines
5.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```
在结构体中也可以指定默认值。