Files
TransPyC/wiki/04-functions.md
T

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

函数修饰符

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

导出函数

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)

规则:

  1. CReturn 中的类型数量决定返回值个数
  2. 必须使用左右值(元组解包)赋值,返回值不能直接传入函数。

指针参数

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

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