Nim 中定义柔性数组
2025-07-01 20:55:10
在 Nim 中定义 Win32 中的 MIB_IPADDRTABLE 结构时产生的一个问题:对于包含动态数组的结构应该如何定义?
#用 array
刚开始时我参考了 winim 中的定义:
1 | MIB_IPADDRTABLE* = object |
看上去和原始结构定义一致,其内存布局也和 C 语言一致:
1 | echo sizeof(MIB_IPADDRTABLE) # 28 bytes |
但是程序运行时会发生崩溃:
1 | Error: execution of an external program failed |
因为这个类型有边界检查,它的大小在编译时确定为1了,在运行时访问第2个元素后会导致程序异常退出。
除非在编译时使用--boundChecks:off选项关闭边界检查,但这会影响整个程序。
#用 UncheckedArray
正确的方法是用 UncheckedArray 类型:
1 | MIB_IPADDRTABLE* = object |
但与用array类型不同的时,结构体大小发生了变化:
1 | echo sizeof(MIB_IPADDRTABLE) # 4 bytes |
显然这个4字节是dwNumEntries的长度,数组的长度是零。看看生成的 C 代码:
1 | struct tyObject_MIB_IPADDRTABLE__9cIn6VOf2jyMBmImLIY4BwA { |
查看源码得知 SEQ_DECL_SIZE 根据条件验证后被定义为不同的值:
1 | /* declared size of a sequence/variable length array: */ |
我用的 VC 编译器,SEQ_DECL_SIZE被定义为空,所以不占用长度。
#array 和 UncheckedArray 的区别
-
大小声明:
array需要在编译时知道确切的大小。例如:array[5, int]。UncheckedArray不需要指定大小。例如:UncheckedArray[int]。
-
边界检查:
array在默认情况下会进行边界检查,除非使用--boundChecks:off编译选项。UncheckedArray不进行任何边界检查,允许在没有运行时检查的情况下访问任何索引。
-
用途:
array通常用于固定大小的数组。UncheckedArray主要用于与 C 代码交互,特别是处理可变长度数组或作为结构体的最后一个成员(柔性数组成员)。
-
内存管理:
array通常作为栈分配或结构体的一部分。UncheckedArray通常与动态内存分配一起使用。
#结论
- 柔性数组成员的位置一定是处于结构体中最后一个位置。
- 定义时的数组长度不重要,因为它只有在运行时才能知道确切的大小。
UncheckedArray基本用在与 C 交互的地方。