Nodejs 有没有用过node-ffi 和 node-ref的朋友?遇到个问题交流下

Nodejs 有没有用过node-ffi 和 node-ref的朋友?遇到个问题交流下

在C 语言中char** 可以做为一维数组使用,在node-ref中如何使用?用ffi 、ref 返回的char** 为什么只有第一个元素!

3 回复

当然可以。node-ffinode-ref 是两个用于 Node.js 的库,它们允许你通过 JavaScript 调用 C 库中的函数。这两个库通常一起使用,其中 node-ref 提供了底层的内存管理和类型系统,而 node-ffi 则提供了一种方法来调用外部函数。

在你的问题中,你提到在 C 语言中 char** 可以作为二维字符数组使用,但在 node-ffinode-ref 中遇到了返回值只包含第一个元素的问题。这通常是由于对指针和数组处理的方式不同导致的。

示例代码

假设我们有一个简单的 C 函数,它返回一个二维字符数组(字符串数组):

// example.c
#include <stdio.h>

void get_strings(char **strings) {
    strings[0] = "Hello";
    strings[1] = "World";
}

编译这个 C 文件生成动态链接库:

gcc -shared -o example.so -fPIC example.c

接下来,我们尝试在 Node.js 中调用这个函数,并处理返回的 char**

const ref = require('ref');
const ffi = require('ffi-napi');

// 定义 C 函数签名
const charPtr = ref.refType(ref.types.CString);
const charPtrArray = new Array(2).fill(charPtr);

const lib = ffi.Library('./example', {
    'get_strings': ['void', [charPtrArray]]
});

// 创建一个 char** 类型的缓冲区
const stringsBuffer = ref.alloc(charPtrArray);

// 调用 C 函数
lib.get_strings(stringsBuffer);

// 解析结果
for (let i = 0; i < 2; i++) {
    const str = ref.deref(stringsBuffer.getAddress(i));
    console.log(str); // 输出: Hello, World
}

解释

  1. 定义 C 函数签名:我们需要正确地定义 C 函数的输入和输出类型。
  2. 创建缓冲区char** 在 C 中是一个指向指针的指针,因此我们需要创建一个 char* 数组的缓冲区。
  3. 调用 C 函数:将缓冲区传递给 C 函数,让其填充数据。
  4. 解析结果:通过 ref.deref 方法获取每个指针指向的实际字符串。

如果你在 node-ffinode-ref 中遇到只返回第一个元素的问题,可能是因为没有正确地分配或解析指针数组。确保在调用 C 函数之前正确地初始化了缓冲区,并且在读取结果时正确地解引用了指针。


对于这个问题,node-ffinode-ref 都是用于与C语言库进行交互的工具。当在C语言中使用 char** 时,它通常被用来表示一个字符串数组(例如命令行参数)。在Node.js环境中,我们可以通过ref模块来处理这些指针。

下面是一个简单的示例代码,展示如何在Node.js中使用node-ffinode-ref处理char**类型的数据:

const ref = require('ref');
const ffi = require('ffi-napi');

// 定义char**
const CharPtrType = ref.refType(ref.types.CString);
const CharPtrPtrType = ref.refType(CharPtrType);

// 创建一个字符串数组
const strArray = ['Hello', 'World'];
const charArray = new Array(strArray.length).fill(0).map(() => ref.allocCString(''));

strArray.forEach((str, index) => {
    ref.writePointer(charArray[index], 0, ref.types.CString);
});

// 创建指向字符串数组的指针
const charArrayPtr = ref.address(charArray);

// 使用ffi调用C函数
const myLib = new ffi.Library('./mylib', {
    'myFunction': [/* 返回类型 */, [CharPtrPtrType]]
});
const result = myLib.myFunction(charArrayPtr);

console.log(result);

在这个示例中,我们首先定义了char*char**类型的引用。然后创建了一个字符串数组,并将其转换为char**类型的指针。最后,通过ffi调用一个C函数并传入该指针。

解释

  1. 定义指针类型ref.refType用于定义指针类型。
  2. 创建字符串数组new Array(strArray.length)创建了一个新的数组,并填充了指定长度的空指针。
  3. 填充数组:使用ref.writePointer将每个字符串写入到数组中的指针位置。
  4. 获取指针地址:使用ref.address获取整个字符串数组的指针地址。
  5. 调用C函数:通过ffi.Library加载C库,并定义需要调用的函数,其中包含char**类型的参数。

如果遇到只有第一个元素的情况,可能是因为内存管理或指针传递不正确导致的,确保每一步都正确处理了指针和数据。

回到顶部