Nim 中定义柔性数组
2024-12-25 08:33:40
在 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 交互的地方。