Files
Viper_Wiki/03-variables.md

7.5 KiB
Raw Permalink Blame History

03 - 变量声明与赋值

Viper 的变量声明使用 Python 的类型注解语法,通过注解指定 C 级别的类型信息。

类型书写规范:优先用短名别名(int/uchar/uint64/bool…)、T* 指针、前缀数组 [N]T,尽量少用 |。详见 02-type-system.md 类型书写规范。

带注解的变量声明

使用 变量名: 类型 语法声明变量:

x: int = 0                       # int x = 0;
y: uint32 = 42                   # uint32_t y = 42;
name: [64]char                   # char name[64];
ptr: void*                       # void* ptr;
msg: const char* = "Hello"       # const char* msg = "Hello";

无初始值的声明

模块级(全局)无初值声明生成零初始化的全局变量(LLVM zeroinitializer,零初始化成立):

count: int                       # int count = 0;(zeroinitializer;仅模块级成立)
buffer: [256]char                # char buffer[256] = {0};

函数内局部无初值声明仅分配空间、不初始化——值未定义,勿假定为 0,最好预先赋值或用 memset 清除:

tmp: int                         # 函数内局部:仅分配未初始化(值未定义,勿假定为 0)

延迟赋值

变量可以先声明后赋值:

x: int
x = 10

指针变量

p:       int*              # int* p;
fb:      void*             # void* fb;
str_ptr: const char*       # const char* str_ptr;

指针变量的特殊初始化

指针判空可直接赋 None:

p: void* = None            # void* p = NULL;

旧的显式写法 t.CVoid(0, t.CPtr) 仍可用,但不推荐。

普通赋值

x: int = 0
x = 42                     # x = 42;

增强赋值

支持所有 Python 增强赋值运算符:

x: int = 0
x += 1                     # x += 1;
x -= 1                     # x -= 1;
x *= 2                     # x *= 2;
x //= 3                    # x /= 3; (整数除法)
x %= 5                     # x %= 5;
x <<= 1                    # x <<= 1;
x >>= 1                    # x >>= 1;
x |= 0xFF                  # x |= 0xFF;
x &= 0x0F                  # x &= 0x0F;
x ^= 0xAA                  # x ^= 0xAA;

指针读写

指针的取地址 / 解引用用 & / *(取代 c.Addr / c.Deref / c.DerefAs / c.Load):

v: int = 42
p: int* = &v               # 取地址
*p = 7                     # 解引用写入(≡ c.DerefAs)
w: int = *p                # 解引用读取(≡ c.Deref)
*q = *p                    # 内存拷贝(≡ c.Load)

volatile 限定

volatile 是软关键字,用于变量声明 / 赋值 / 值位置的调用前缀,使对应的 load / store 落 LLVM volatile:

volatile flag: int = 0     # volatile int flag;
flag = 1                   # volatile store
v: int = volatile f()      # 值位置:调用结果槽 volatile 存取

LLVM 的 call 指令本身没有 volatile 限定符,因此 volatile 语义只落在内存存取上:构造会逐字段 store volatile,并在 __new__ / __before_init__ / __init__ 调用后追加一次 volatile 屏障。

全局变量

模块顶层声明的变量即为全局变量:

kbd_tid: int = -1          # 全局 int kbd_tid = -1;
BootInfo: bootinfo*        # 全局 struct bootinfo* BootInfo;

静态全局变量

static x: int = 0                # static int x = 0;(前置软关键字,推荐)
y: t.CStatic | t.CInt = 0        # 等价链式标记写法

static 符号仅限定义模块内可见:跨模块取值(mod.x)、调用(mod.f())、from mod import x 三种形态都会编译期 NameError fail-fast(定义侧登记 + 引用侧拦截)。旧写法 x: static t.CInt(static 写在注解位置)已不再支持,会明确报错。

外部声明

extern errno: int                # extern int errno;(前置软关键字,推荐)
fd: t.CExtern | int              # 等价链式标记写法(内部标记)

模块级 extern 全局生成 @裸名 = external global T(external linkage、无初始值、无 storage),符号由外部(C 库 / 汇编 / 其它翻译单元)提供;不允许带初始值。

export 也可用于变量(裸名导出、可带初始值):

export tss_buf: [104]uint8       # 裸名导出全局(无初始值时零初始化)

重复声明规则(硬约定)

模块级已有同名变量时,函数内再次用类型注解声明同名变量一律 fail-fast(TypeError,判据不含类型是否一致):

count: int = 0

def f() -> void:
    count: int = 1     # ❌ TypeError:count 已是模块级变量,未声明 global 时不得再用注解声明同名变量

两种情形都报错:

  • 无 global / nonlocal:会把全局遮蔽成局部 → 重复声明;
  • 有 global / nonlocal 后再用注解重新声明 → 同样重复声明。

合法写法只有两种:

count: int = 0

def f() -> void:
    global count
    count = 1             # ✅ 修改全局:global + 无注解赋值
  1. 修改全局:函数内 global x + 无注解赋值 x = v;
  2. 独立局部:换一个不与全局重名的变量名。

仅函数内生效;模块级自身的重复注解不走此检查。

另:读全局变量无需 global,仅读取不报错;写全局且未声明 global 才报错。

常量定义

编译期常量推荐用 define 软关键字(等价旧写法 X: t.CDefine = Y):

define MAX_SIZE = 1024           # 推荐:自动推断底层类型
define PAGE_SIZE: uint32 = 4096  # 带显式底层类型
MAX_SIZE2: t.CDefine = 1024      # 等价旧写法

t.CDefine 不是数据类型,而是编译时元指令——常量在 LLVM IR 中不生成全局变量,而是在引用处直接内联展开。详见 README.MD 中 t.CDefine 深度解析。

define 有两种形态:带 =(define X: T = Y / define X = Y)是编译期常量;带 ((define F(...) -> T)是宏函数。详见 04-functions.md 宏函数。

字符串常量

Viper 中的字符串字面量编译为 C 的字符串常量(const char*):

msg: const char* = "Hello, World!"
serial.puts(msg)

也可以直接传递字符串字面量:

serial.puts("Hello, World!")

类型转换

使用类型构造函数进行显式类型转换:

x: int = 42
y: uint32 = uint32(x)     # (uint32_t)x
f: float = float(x)       # (float)x
i: int = int(f)           # (int)f

指针类型转换

ptr: void* = some_ptr
int_val: uint64 = uint64(ptr)   # (uint64_t)ptr — 指针转整数(需显式)

隐式转换不允许指针 ↔ 整数(唯一豁免编译期常量 0);显式强转可以。

结构体实例化

此处不理解参见 05-classes.md 中 结构体实例化与初始化

直接使用类名作为构造函数:

info: fat32_types.fat32_fileinfo
dp: fat32_types.fat32_dirobj

带初始化的实例化:

obj: MyClass = MyClass(arg1, arg2)

使用 & 获取实例指针:

obj_ptr: MyClass* = &MyClass(arg1, arg2)

delete 语句

del 语句可用于调用对象的 __del__ 或 __delete__ 方法:

del obj        # 调用 obj.__del__() 或 obj.__delete__()
del arr[idx]   # 调用 arr.__delitem__(idx)