# 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` 差，实际工程中不推荐使用条件宏，后期将完善宏的设计，引入模板等。

## FFI 外部函数声明

Viper 的 FFI（Foreign Function Interface）**无需任何特殊语法**——仅靠返回类型注解中的 `t.State` 标记即可声明外部函数。`t.State` 是声明性标记类型，表示"仅声明不定义"（语义等价于 `t.CExport | t.CExtern`），编译器只生成 `declare` 原型，不生成 `define` 函数体，由链接器在外部库中解析符号。

### 基本声明

函数体为 `pass`，返回类型用 `RetType | t.State`：

```python
def isr0() -> t.CVoid | t.State: pass        # extern void isr0();  — 来自汇编或外部
def getchar() -> t.CInt | t.State: pass      # extern int getchar(); — 来自 libc
```

编译为 LLVM IR：

```llvm
declare void @"isr0"()        ; 不加 SHA1 前缀（t.State 含 CExport 语义）
declare i32  @"getchar"()
```

### Win32 API 绑定示例

[includes/w32](../includes/w32) 中的 Win32 绑定全部通过 `t.State` 声明，零特殊语法：

```python
def CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: ULONG,
                dwShareMode: ULONG,
                lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr,
                dwCreationDisposition: ULONG,
                dwFlagsAndAttributes: ULONG,
                hTemplateFile: HANDLE) -> HANDLE | t.State:
    pass
```

等价 C 声明：

```c
HANDLE CreateFileA(LPCSTR, ULONG, ULONG, SECURITY_ATTRIBUTES*,
                   ULONG, ULONG, HANDLE);
```

链接时通过 `project.json` 指定外部库（如 `kernel32.lib`、`user32.lib`），链接器解析这些符号。

### `t.State` 与 `t.CExtern` 的区别

| 修饰 | SHA1 前缀 | 生成内容 | 用途 |
|------|----------|---------|------|
| 无修饰 | ✅ 加前缀 | `declare` + `define` | 模块私有函数 |
| `t.CExtern` | ❌ 不加 | `declare`（引用外部） | 引用外部 C 函数 |
| `t.CExport` | ❌ 不加 | `declare` + `define` | 对外暴露 API |
| `t.State` | ❌ 不加 | 仅 `declare` | FFI 外部函数声明（= `CExport \| CExtern`） |

### 声明外部全局变量

外部全局变量通过 `t.CExtern` 注解声明：

```python
errno: t.CExtern | t.CInt        # extern int errno;
```

详见 [02-type-system.md 的 t.State 章节](02-type-system.md#tstate-声明性标记) 和 [includes/w32](../includes/w32) 的 Win32 绑定实现。

## 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#运算符重载)。
