Files
ViperOS/vpsdk/wiki/02-type-system.md
2026-07-19 12:38:20 +08:00

20 KiB
Raw Permalink Blame History

02 - 类型系统

Viper 的类型系统通过 t 模块提供,所有类型注解继承 t.CType 。大都以 t.C{TypeName:PascalCase}为类型,类型注解是 Viper 的核心机制,决定了变量的内存布局、大小和对齐方式。

基本类型

整数类型

Viper 类型 C 等价 大小(位) 有符号
t.CChar char 8
t.CShort short 16
t.CInt int 32
t.CLong long 64
t.CUnsignedChar unsigned char 8
t.CUnsignedShort unsigned short 16
t.CUnsigned / t.CUnsignedInt unsigned int 32
t.CUnsignedLong unsigned long 64
t.CSignedChar signed char 8

值得注意的是t.CUnsigned 一般不单独使用,而是配合其它有符号类型,替换表示无符号,比如 t.CUnsigned | t.CInt,由于为了便于使用一些常用类型,则将其组合为常用的 t.CUnsignedInt 等。

固定宽度整数类型

Viper 类型 C 等价 大小(位) 有符号
t.CInt8T int8_t 8
t.CInt16T int16_t 16
t.CInt32T int32_t 32
t.CInt64T int64_t 64
t.CUInt8T uint8_t 8
t.CUInt16T uint16_t 16
t.CUInt32T uint32_t 32
t.CUInt64T uint64_t 64

最小宽度整数类型

Viper 类型 C 等价 大小(位) 有符号
t.CIntLeast8T int_least8_t ≥8
t.CIntLeast16T int_least16_t ≥16
t.CIntLeast32T int_least32_t ≥32
t.CIntLeast64T int_least64_t ≥64
t.CUIntLeast8T uint_least8_t ≥8
t.CUIntLeast16T uint_least16_t ≥16
t.CUIntLeast32T uint_least32_t ≥32
t.CUIntLeast64T uint_least64_t ≥64

最快最小宽度整数类型

Viper 类型 C 等价 大小(位) 有符号
t.CIntFast8T int_fast8_t ≥8
t.CIntFast16T int_fast16_t ≥16
t.CIntFast32T int_fast32_t ≥32
t.CIntFast64T int_fast64_t ≥64
t.CUIntFast8T uint_fast8_t ≥8
t.CUIntFast16T uint_fast16_t ≥16
t.CUIntFast32T uint_fast32_t ≥32
t.CUIntFast64T uint_fast64_t ≥64

最大宽度整数类型

Viper 类型 C 等价 大小(位) 有符号
t.CIntMaxT intmax_t ≥64
t.CUIntMaxT uintmax_t ≥64

stdint 短名别名

通过 import stdint 引入,这些短名是上述类型的 t.CTypedef 别名,便于在系统编程场景中快速使用。允许直接使用 from stdint import * 来直接使用。

基本类型短名

短名 等价展开 说明
stdint.INT t.CInt -
stdint.UINT t.CUnsignedInt -
stdint.BOOL t.CInt 1 为真0 为假
stdint.SHORT t.CShort -
stdint.USHORT t.CUnsignedShort -
stdint.LONG t.CLong -
stdint.ULONG t.CUnsignedLong -
stdint.LONGLONG t.CLong | t.CLong -
stdint.ULONGLONG t.CUnsignedLong | t.CLong -
stdint.FLOAT t.CFloat -
stdint.DOUBLE t.CDouble -

固定宽度短名

短名 等价展开
stdint.INT8 t.CInt8T
stdint.INT16 t.CInt16T
stdint.INT32 t.CInt32T
stdint.INT64 t.CInt64T
stdint.UINT8 t.CUInt8T
stdint.UINT16 t.CUInt16T
stdint.UINT32 t.CUInt32T
stdint.UINT64 t.CUInt64T

字节与字短名

短名 等价展开 说明
stdint.BYTE t.CUnsignedChar 8 位无符号
stdint.WORD t.CUInt16T 16 位无符号
stdint.DWORD t.CUInt32T 32 位无符号
stdint.QWORD t.CUInt64T 64 位无符号

字符类型短名

短名 等价展开 说明
stdint.TCHAR t.CChar -
stdint.CHARLIST str | t.CPtr / list[str, None] -
stdint.WCHAR stdint.WORD UTF-16 代码单元
stdint.CHAR8 t.CChar8T -
stdint.CHAR16 t.CChar16T -
stdint.CHAR32 t.CChar32T -

指针短名

短名 等价展开
stdint.INTPTR t.CInt | t.CPtr
stdint.UINTPTR t.CUnsignedInt | t.CPtr
stdint.BYTEPTR stdint.BYTE | t.CPtr
stdint.SHORTPTR t.CShort | t.CPtr
stdint.USHORTPTR t.CUnsignedShort | t.CPtr
stdint.WCHARPTR stdint.WORD | t.CPtr
stdint.VOIDPTR t.CVoid | t.CPtr
stdint.INT8PTR t.CInt8T | t.CPtr
stdint.INT16PTR t.CInt16T | t.CPtr
stdint.INT32PTR t.CInt32T | t.CPtr
stdint.INT64PTR t.CInt64T | t.CPtr
stdint.UINT8PTR t.CUInt8T | t.CPtr
stdint.UINT16PTR t.CUInt16T | t.CPtr
stdint.UINT32PTR t.CUInt32T | t.CPtr
stdint.UINT64PTR t.CUInt64T | t.CPtr
stdint.CHAR8PTR t.CChar8T | t.CPtr
stdint.CHAR16PTR t.CChar16T | t.CPtr
stdint.CHAR32PTR t.CChar32T | t.CPtr

平台特定短名

短名 等价展开 说明
stdint.FSIZE_t stdint.DWORD 文件大小
stdint.LBA_t stdint.DWORD 逻辑块地址

平台相关类型

Viper 类型 C 等价 大小(位) 有符号
t.CSizeT size_t 64
t.CIntPtrT intptr_t 64
t.CUIntPtrT uintptr_t 64
t.CPtrDiffT ptrdiff_t 64

stdint 短名别名

Viper 在 stdint 模块中提供了更简短的类型别名,通过 t.CTypedef 映射到对应的完整类型。使用时需 import stdint

固定宽度整数短名

短名 等价 Viper 类型 C 等价
INT8 t.CInt8T int8_t
INT16 t.CInt16T int16_t
INT32 t.CInt32T int32_t
INT64 t.CInt64T int64_t
UINT8 t.CUInt8T uint8_t
UINT16 t.CUInt16T uint16_t
UINT32 t.CUInt32T uint32_t
UINT64 t.CUInt64T uint64_t

固定宽度指针短名

短名 等价 Viper 类型 C 等价
INT8PTR t.CInt8T | t.CPtr int8_t*
INT16PTR t.CInt16T | t.CPtr int16_t*
INT32PTR t.CInt32T | t.CPtr int32_t*
INT64PTR t.CInt64T | t.CPtr int64_t*
UINT8PTR t.CUInt8T | t.CPtr uint8_t*
UINT16PTR t.CUInt16T | t.CPtr uint16_t*
UINT32PTR t.CUInt32T | t.CPtr uint32_t*
UINT64PTR t.CUInt64T | t.CPtr uint64_t*

字符类型短名

短名 等价 Viper 类型 C 等价
CHAR8 t.CChar8T char8_t
CHAR16 t.CChar16T char16_t
CHAR32 t.CChar32T char32_t
CHAR8PTR t.CChar8T | t.CPtr char8_t*
CHAR16PTR t.CChar16T | t.CPtr char16_t*
CHAR32PTR t.CChar32T | t.CPtr char32_t*

基本类型短名

短名 等价 Viper 类型 C 等价
INT t.CInt int
UINT t.CUnsignedInt unsigned int
BOOL t.CInt int0/1
SHORT t.CShort short
USHORT t.CUnsignedShort unsigned short
LONG t.CLong long
ULONG t.CUnsignedLong unsigned long
LONGLONG t.CLong | t.CLong long long
ULONGLONG t.CUnsignedLong | t.CLong unsigned long long
FLOAT t.CFloat float
DOUBLE t.CDouble double

平台 / Windows 风格短名

短名 等价 Viper 类型 C 等价
BYTE t.CUnsignedChar unsigned char8位
BYTEPTR BYTE | t.CPtr unsigned char*
WORD t.CUInt16T uint16_t16位
DWORD t.CUInt32T uint32_t32位
QWORD t.CUInt64T uint64_t64位
INTPTR t.CInt | t.CPtr int*
UINTPTR t.CUnsignedInt | t.CPtr unsigned int*
SHORTPTR t.CShort | t.CPtr short*
USHORTPTR t.CUnsignedShort | t.CPtr unsigned short*
VOIDPTR t.CVoid | t.CPtr void*
TCHAR t.CChar char
WCHAR WORD uint16_tUTF-16
WCHARPTR WORD | t.CPtr uint16_t*UTF-16
CHARLIST str | t.CPtr char*
FSIZE_t DWORD uint32_t
LBA_t DWORD uint32_t

浮点类型

Viper 类型 C 等价 大小(位)
t.CFloat float 32
t.CDouble double 64

其他基本类型

Viper 类型 C 等价 说明
t.CVoid void 空类型
t.CBool bool 布尔类型8位
t.CWCharT wchar_t 宽字符32位
t.CChar8T char8_t UTF-8 字符8位无符号
t.CChar16T char16_t UTF-16 字符16位无符号
t.CChar32T char32_t UTF-32 字符32位无符号

Python 便捷映射类型

Python 类型 Viper 类型 Viper 值
int t.CInt -
float t.CFloat -
str t.CChar | t.CPtr -
bool t.CBool -
True t.CBool 1
False t.CBool 0
None NULL t.CIntPtr(0)

对于 t.py 和 c.py 的引用,必须使用 import不能使用 from ... import ...,也不能使用 as因为这两者都是直接以字符串识别的。

类型组合

Viper 使用 Python 的 | 来组合类型修饰符TypeUnion其仅在左值注解中有效其它位置均为位或语义至少重载前是这样的这是 Viper 最重要的语法特性之一。

指针类型

使用 t.CPtr 表示指针,通过 | 与基本类型组合:

x: t.CInt  | t.CPtr          # int* — 指向 int 的指针
p: t.CVoid | t.CPtr         # void* — 通用指针
s: t.CChar | t.CPtr         # char* — 字符串指针
pp: t.CInt | t.CPtr | t.CPtr  # int** — 指向指针的指针

等价 C 代码:

int* x;
void* p;
char* s;
int** pp;

同时,指针也可以用 Ptr[T] 的方法表示,但在 Viper 中不太推荐,虽然说这样做一直是类似工程的常见用法,但是如果此处 T 是一个多态,同时我们想要复用 Python 的高亮插件,插件无法识别 Ptr[T] 的属性取值,但是对于 T | Ptr 可以。

x: t.CPtr[t.CInt]
p: t.CPtr[t.CVoid]
s: t.CPtr[t.CChar]
pp: t.CPtr[t.CPtr[t.CInt]]
pp2: t.CInt | t.CPtr[t.CPtr] # 同时也可以这么表示

等价 C 代码:

int* x;
void* p;
char* s:
int** pp;
int** pp2;

类型限定符组合

x: t.CConst | t.CInt        # const int
p: t.CConst | t.CChar | t.CPtr  # const char*

存储类组合

x: t.CStatic | t.CInt       # static int
f: t.CExtern | t.CInt       # extern int声明其存在于外部

函数返回类型组合

def foo() -> t.CInt | t.CExport:     # 导出函数,返回 int
    return 0

def bar() -> t.CVoid | t.CExtern:    # 外部函数声明
    pass

t.State 声明性标记

t.State声明性标记类型,表示"仅声明不定义"(语义等价于 t.CExport | t.CExtern)。主要用于 FFI 外部函数声明:函数体为 pass编译器只生成函数原型declare不生成定义define由链接器在外部库中解析符号。

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

等价 C 声明:

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

t.State 是 Viper FFI 机制的核心,无需任何特殊语法,仅靠返回类型注解即可声明外部函数。详见 08-c-operations.md 的 FFI 章节includes/w32 的 Win32 绑定。

数组类型

使用 Python 的 list[ElementType, Size] 语法表示固定大小数组(通常的,这用于栈上和 BSS 段上):

buf: list[t.CChar, 64]           # char buf[64]
ids: list[t.CInt, 10]            # int ids[10]
matrix: list[t.CFloat, 16]       # float matrix[16]
entries: list[idt_entry, 256]    # struct idt_entry entries[256]
s: list[t.CChar, None]           # 自推长度 char s[];

等价 C 代码:

char buf[64];
int ids[10];
float matrix[16];
struct idt_entry entries[256];

数组指针和函数指针

lp: list[t.CInt, 12] | t.CPtr
vp: t.Callable[[t.CInt, t.CInt], t.CInt] = x # 其中 t.Callable = typing.Callable可以直接使用。

结构体类型

使用 class 定义结构体,成员通过类型注解声明:

class point:
    x: t.CInt
    y: t.CInt

等价 C 代码:

struct point {
    int x;
    int y;
};

带指针成员的结构体

class node:
    value: t.CInt
    next: node | t.CPtr     # struct node* next

匿名结构体成员(

WARNING: 警告: 由于 Viper 在声明结构体,枚举等处不需要关键字,因此 t.Anonymouse 是不需要使用的。此关键字不再维护,强行使用可能导致未定义行为。

继承 t.Anonymous 的类作为匿名成员嵌入:

class header(t.Anonymous):
    magic: t.CUInt32T
    version: t.CUInt32T

class packet:
    header          # 匿名嵌入,可直接访问 packet.magic
    length: t.CUInt32T

字节序标记

WARNING: 警告: 此关键字是实验性的。未经充分测试,不当使用可能导致未定义行为。

使用 t.BigEndiant.LittleEndian 标记成员的字节序:

class network_packet:
    length: t.CUInt16T | t.BigEndian     # 大端序存储
    type: t.CUInt8T                       # 默认小端序

联合体类型

继承 t.CUnion 定义联合体:

class value(t.CUnion):
    ival: t.CInt
    fval: t.CFloat
    pval: t.CVoid | t.CPtr

等价 C 代码:

union value {
    int ival;
    float fval;
    void* pval;
};

枚举类型

继承 t.CEnum 定义枚举:

class color(t.CEnum):
    RED: t.CEnum = 0
    GREEN: t.CEnum = 1
    BLUE: t.CEnum = 2

等价 C 代码:

enum color {
    RED = 0,
    GREEN = 1,
    BLUE = 2
};

枚举成员可直接使用名称:

c: t.CInt = color.RED

REnum标签联合体

t.CEnum 是普通枚举(整数常量集合),t.REnum标签联合体tagged union / Rust enum 风格)。每个变体可携带不同的 payload通过 match 模式匹配分派。适用于少变体、无通用字段、match 分派的场景如类型系统、IR 表示)。

class LLVMType(t.REnum):
    class Int:
        Bits: t.CInt
    class Void:
        pass

match ty:
    case LLVMType.Int:
        snprintf(buf, size, "i%d", ty.Bits)
    case LLVMType.Void:
        string.strcpy(buf, "void")

REnum 的详细用法、与 CEnum/胖节点 AST 的对比见 05-classes.md 的 REnum 章节

Typedef

使用 t.CTypedef 创建类型别名:

irq_handler_t: t.CTypedef | t.Callable[[], t.CInt]   # typedef int (*irq_handler_t)();

或通过注解赋值:

MyStruct: t.CTypedef = original_struct   # typedef struct original_struct MyStruct;

更推荐通过后者的形式,前者编译器不一定能够识别到注解是对 t.CTypedef 的,还是后面的注解的,而且容易触发未定义行为。

泛型类型PEP 695 语法)

Viper 支持 PEP 695 泛型语法 class Name[T]:,定义类型参数化的类。类型参数 T 在类体内可作为占位类型使用,实例化时用 Name[ConcreteType] 特化。

@t.NoVTable
class GSList[T]:
    Head: T | t.CPtr
    Tail: T | t.CPtr
    Count: t.CSizeT

lst: GSList[GNode] | t.CPtr = GSList[GNode]()

泛型类还支持递归泛型继承(如 class GNode(GSListNode[GNode])),实现强类型自引用结构,无需 void* + 转型。这是 C/C++/Rust 均无法如此简洁表达的能力。

泛型类的完整用法、递归继承、实例化示例见 05-classes.md 的泛型类章节

强制类型转换

在 Viper 中的强制类型转换有些不同,强制类型转换有两种方案,都是基于 t.CType 的用法,符合 Python 本意。 对于原先就继承自 t.CType 的类型来说,可以直接使用 call 的方法进行类型转换,比如

x: t.CChar | t.CPtr = "Hello"
t.CVoid(x, t.CPtr)

其中用法为 t.CType(x, ...),此处...可以是其它的 t.CType 或将要提到的 Typedef,将其视为组合类型对 x 进行强制转换。

额外补充一句,对于比较,四则运算,可以不使用强制类型转换,而是依靠隐式类型转换,但如果是严谨数学计算,推荐还是强制类型转换避免判断出错。

此外,若将一个不同类型的右值赋值到左值,则会隐式将右值转换为左值的类型。

如果你不喜欢 t.CVoid(x, t.CPtr) 的方法,认为这将 voidptr 分开,不便于理解,那么还有一个方法,即将二者打包为一个 Typedef

VOIDPTR: t.CTypedef = t.CVoid | t.CPtr

则如果你想,你可以直接通过 call 的方式进行强转,比如:

y: VOIDPTR = VOIDPTR(x)

宏定义常量

使用 t.CDefine 定义编译时常量。t.CDefine 不是数据类型,而是编译时元指令——标记为 t.CDefine 的常量在 LLVM IR 中不生成任何全局变量,而是在引用处直接内联展开。详见 01-overview.md 中 t.CDefine 深度解析

MAX_SIZE: t.CDefine = 1024
PAGE_SIZE: t.CDefine = 4096
FA_READ: t.CDefine = 0x01

语义上等价于 C 的 #define

#define MAX_SIZE 1024
#define PAGE_SIZE 4096
#define FA_READ 0x01

宏定义支持表达式:

CPU_FEATURE_FPU: t.CDefine = (1 << 0)
CPU_FEATURE_APIC: t.CDefine = (1 << 6)

宏定义也可与类型组合使用:

CODE_SEG: t.CDefine | t.CUInt16T = 0x08

位域

使用 t.Bit(n) 定义位域成员:

class flags:
    a: t.CUInt32T | t.Bit[1] # 此处,如果存入 2二进制是 10会被截断为 0
    b: t.CUInt32T | t.Bit[3]
    c: t.CUInt32T | t.Bit[4]

LLVM IR 类型简写

Viper 提供了 LLVM IR 级别的类型简写:

i1   # 1位整数
i8   # 8位有符号整数
i16  # 16位有符号整数
i32  # 32位有符号整数
i64  # 64位有符号整数
u1   # 1位无符号整数
u8   # 8位无符号整数
u16  # 16位无符号整数
u32  # 32位无符号整数
u64  # 64位无符号整数

仍然通过 t.x 的方式调用,比如 t.i1 等。

__attribute__ 属性

通过 t.attr 命名空间访问 GCC __attribute__ 属性:

t.attr.packed()                    # __attribute__((packed))
t.attr.aligned(16)                 # __attribute__((aligned(16)))
t.attr.section(".text.startup")    # __attribute__((section(".text.startup")))
t.attr.always_inline()             # __attribute__((always_inline))
t.attr.noinline()                  # __attribute__((noinline))
t.attr.noreturn()                  # __attribute__((noreturn))
t.attr.weak()                      # __attribute__((weak))
t.attr.unused()                    # __attribute__((unused))
t.attr.constructor()               # __attribute__((constructor))
t.attr.destructor()                # __attribute__((destructor))
t.attr.deprecated("use X")         # __attribute__((deprecated("use X")))

LLVM 函数属性

通过 t.attr.llvm 命名空间指定 LLVM 函数属性:

t.attr.llvm.nobuiltin
t.attr.llvm.nounwind
t.attr.llvm.noredzone
t.attr.llvm.willreturn
t.attr.llvm.mustprogress
t.attr.llvm.optnone
t.attr.llvm.noinline
t.attr.llvm.alwaysinline
t.attr.llvm.readnone
t.attr.llvm.readonly
t.attr.llvm.writeonly
t.attr.llvm.inaccessiblememonly
t.attr.llvm.inaccessiblemem_or_argmemonly

在函数返回类型注解中使用:

def foo() -> t.CInt | t.attr.llvm.nobuiltin | t.attr.llvm.nounwind:
    return 0