# 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
```

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