Files
TransPyC/wiki/08-c-operations.md
2026-06-16 16:09:42 +08:00

251 lines
6.0 KiB
Markdown
Raw 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.
# 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#运算符重载)。