使用ffi-napi与ref-struct读取16位整数的字节对齐异常问题
核心原因:结构体内存对齐/字段偏移不匹配
你遇到的问题本质是Node.js侧用ref-struct-napi定义的结构体,其内存对齐规则、字段偏移和C++侧的结构体定义不一致,导致读取时取错了内存位置。
数值对应分析
24的十六进制是0x18,小端序在内存中存储为0x18 0x00;而你读到的20480是0x5000,说明实际读取的是内存中0x00 0x50这两个字节——这明显是读取位置偏移了1字节(或更多),把后续字段的字节当成了当前字段的内容。
对齐规则差异的具体场景
比如你的C++结构体可能用了紧凑对齐(比如#pragma pack(push, 1)),示例如下:
#pragma pack(push, 1) struct DataResult { unsigned char StatusFlag; // 偏移0,占1字节 uint16_t Rows; // 偏移1,占2字节 // 其他字段... }; #pragma pack(pop)
但你在Node.js中定义结构体时,默认未指定对齐规则,ref-struct-napi会采用平台默认对齐(Windows下通常是4字节):
// 错误示例:未设置对齐,导致StatusFlag后填充3字节,Rows偏移变为4 const DataResult = refStruct({ StatusFlag: ref.types.uchar, Rows: ref.types.uint16 });
此时Node侧Rows字段的偏移是4,而DLL是往C++结构体的偏移1处写入数据,自然读出来的是错误的字节组合。
而你改成uchar加padding的写法,其实是手动模拟了紧凑对齐的内存布局,让字段偏移和C++侧一致,所以能读到正确值。
解决方案
强制对齐规则匹配
在Node.js中定义结构体时,显式指定对齐参数,和C侧的对齐规则完全一致。如果C用了#pragma pack(1),则Node侧添加{ pack: 1 }参数:// 正确示例:设置紧凑对齐,和C++侧匹配 const DataResult = refStruct({ StatusFlag: ref.types.uchar, Rows: ref.types.uint16 }, { pack: 1 });验证字段偏移
用ref.getFieldOffset工具函数,对比Node侧和C++侧的字段偏移是否一致:// 打印Node侧Rows字段的偏移 console.log(ref.getFieldOffset(DataResult, 'Rows'));同时在C++中用
offsetof宏验证:// 打印C++侧Rows字段的偏移 printf("Rows offset: %zu\n", offsetof(DataResult, Rows));两者必须完全相等才能保证读取正确。
字节序确认(可选)
Windows平台本身是小端序,ref-struct-napi默认会按主机字节序解析数据,只要偏移正确,字节序不会成为问题。如果是跨平台场景,才需要额外处理字节序转换。
内容的提问来源于stack exchange,提问作者manuell

