# 08 - C 语言操作 Viper 通过 `c` 模块提供对 C 语言底层特性的访问,包括指针操作、内联汇编、预处理指令等。 ## 指针操作 ### 取地址 `c.Addr` ```python x: t.CInt = 42 p: t.CInt | t.CPtr = c.Addr(x) # int* p = &x; ``` 对结构体成员取地址: ```python res: t.CInt = fat32.opendir("/", c.Addr(dp)) # res = fat32_opendir("/", &dp); ``` 对数组取地址: ```python viperlib.snprintf(c.Addr(buf), 64, "hello %d", 42) # snprintf(&buf, 64, "hello %d", 42); ``` ### 解引用 `c.Deref` ```python ptr: Sheet | t.CPtr = c.Addr(sheet_obj) obj: Sheet = c.Deref(ptr) # struct Sheet obj = *ptr; ``` ### 内存拷贝 `c.Load` ```python c.Load(ptr, value) # *ptr = *value; ``` ### 解引用赋值 `c.DerefAs` ```python c.DerefAs(ptr, value) # *ptr = value; ``` ### 赋值 `c.Set` ```python c.Set(target, value) # target = value; ``` ## 内联汇编 `c.Asm` Viper 提供了声明式的内联汇编语法,编译为 GCC 风格的 `__asm__ __volatile__` 语句。 ### 基本用法 ```python c.Asm("nop") # __asm__ __volatile__("nop"); ``` ### 带操作数的汇编 使用 f-string 和 `c.AsmInp` / `c.AsmOut` 标记操作数: ```python saved_rdi: t.CUnsignedLong c.Asm(f"mov {c.AsmOut(saved_rdi, t.ASM_DESCR.OUTPUT_REG)}, rdi", op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RDI]) ``` 等价 C 代码: ```c __asm__ __volatile__( "mov %0, rdi" : "=r"(saved_rdi) : : "memory", "rdi" ); ``` ### 输入操作数 `c.AsmInp` ```python msg: t.CConst | t.CChar | t.CPtr = "Hello" c.Asm(f"mov rdi, {c.AsmInp(msg, t.ASM_DESCR.REG_ANY)}", op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX]) ``` ### 完整示例 ```python c.Asm(f"""mov rdi, {c.AsmInp(msg, t.ASM_DESCR.REG_ANY)} call {c.AsmInp(log_info_fn, t.ASM_DESCR.REG_ANY)}""", op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9, t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11]) ``` ### ASM_DESCR 约束字符 #### 操作数修饰符 | 常量 | 值 | 说明 | |------|----|------| | `MODIFIER_OUTPUT` | `=` | 输出操作数 | | `MODIFIER_READWRITE` | `+` | 读写操作数 | | `MODIFIER_INPUT` | `` | 输入操作数(默认) | | `MODIFIER_GLOBAL` | `&` | 全局操作数 | #### 寄存器约束 | 常量 | 值 | 说明 | |------|----|------| | `REG_ANY` | `r` | 任何通用寄存器 | | `REG_EAX` / `REG_RAX` | `a` | EAX/RAX | | `REG_EBX` / `REG_RBX` | `b` | EBX/RBX | | `REG_ECX` / `REG_RCX` | `c` | ECX/RCX | | `REG_EDX` / `REG_RDX` | `d` | EDX/RDX | | `REG_ESI` / `REG_RSI` | `S` | ESI/RSI | | `REG_EDI` / `REG_RDI` | `D` | EDI/RDI | | `REG_XMM` | `x` | XMM 寄存器 | #### 内存与立即数 | 常量 | 值 | 说明 | |------|----|------| | `MEMORY` | `m` | 内存操作数 | | `IMMEDIATE` | `i` | 立即数 | | `ANY` | `g` | 通用寄存器/内存/立即数 | #### 预定义组合约束 | 常量 | 值 | 说明 | |------|----|------| | `OUTPUT_REG` | `=r` | 输出,通用寄存器 | | `OUTPUT_MEM` | `=m` | 输出,内存 | | `OUTPUT_EAX` | `=a` | 输出,EAX/RAX | | `INPUT_REG` | `r` | 输入,通用寄存器 | | `INPUT_MEM` | `m` | 输入,内存 | | `INPUT_IMM` | `i` | 输入,立即数 | #### 破坏描述符 | 常量 | 说明 | |------|------| | `CLOBBER_EAX` / `CLOBBER_RAX` | 破坏 EAX/RAX | | `CLOBBER_EBX` / `CLOBBER_RBX` | 破坏 EBX/RBX | | `CLOBBER_ECX` / `CLOBBER_RCX` | 破坏 ECX/RCX | | `CLOBBER_EDX` / `CLOBBER_RDX` | 破坏 EDX/RDX | | `CLOBBER_ESI` / `CLOBBER_RSI` | 破坏 ESI/RSI | | `CLOBBER_EDI` / `CLOBBER_RDI` | 破坏 EDI/RDI | | `CLOBBER_CC` | 破坏条件码(标志寄存器) | | `CLOBBER_MEMORY` | 破坏内存 | | `CLOBBER_R8` ~ `CLOBBER_R15` | 破坏 R8~R15 | ## 预处理指令 Viper 通过 `c` 模块的函数调用实现 C 预处理指令。 ### #define ```python c.CDefine("MAX_SIZE", 1024) # #define MAX_SIZE 1024 ``` 上述方法容易引起未定义行为,至少是不便于理解,更常用的方式是使用类型注解: ```python MAX_SIZE: t.CDefine = 1024 # #define MAX_SIZE 1024 ``` ### 条件编译 ```python c.CIfndef(HEADER_H) # #ifndef HEADER_H c.CDefine(HEADER_H) # #define HEADER_H c.CEndif() # #endif ``` ```python c.CIfdef(DEBUG) # #ifdef DEBUG c.CEndif() # #endif ``` ```python c.CIf(VERSION > 2) # #if VERSION > 2 c.CElif(VERSION > 1) # #elif VERSION > 1 c.CElse() # #else c.CEndif() # #endif ``` ### #undef ```python c.Undef(MACRO_NAME) # #undef MACRO_NAME ``` ### #error ```python c.CError("Platform not supported") # #error "Platform not supported" ``` ### #pragma > 此关键字已不再支持 ```python c.CPragma("GCC diagnostic push") # #pragma GCC diagnostic push ``` ### ## 连接符 > 此方法可能已经不再支持 ```python c.TokenPast("PREFIX_", "NAME") # PREFIX_ ## NAME ``` 由于编译器设计,以及不需要像 `C` 一样做大量字符替换,对于上述所有的条件宏都远比 `C` 差,实际工程中不推荐使用条件宏,后期将完善宏的设计,引入模板等。 ## 仅声明 `c.State` `c.State` 用于声明但不定义函数或变量: ```python def isr0() -> t.CExtern | t.CVoid | c.State: pass # extern void isr0(); ``` ## LLVM IR 内联 ### c.LLVMIR 直接嵌入 LLVM IR 指令来实现高效且跨平台的汇编操作: ```python c.LLVMIR(f"add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) ``` ### c.LInp / c.LOut 标记 LLVM IR 的输入/输出操作数: ```python c.LInp(expr) # 输入操作数 c.LOut(expr) # 输出操作数 ``` ## 运算符重载 `@t.Object` 类支持运算符重载,详见 [06-oop.md 中 运算符重载](06-oop.md#运算符重载)。