You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Dart中通过FFI向C函数传递argv[]参数?

解决Dart FFI调用C函数时构造argv的问题

你当前的思路误解了C语言中argv的结构——它不是一个包含多个空字符的单一字符串,而是一个指针数组:每个元素指向一个以null结尾的独立字符串,最后一个元素是NULL指针用来标记数组结束。Dart字符串确实无法包含空字符,所以我们需要换一种方式来构造符合C规范的argv。

正确构造C风格argv的步骤

  • 先把所有命令行参数整理成Dart字符串列表,对应C里每个独立的argv元素
  • 将每个字符串转换为Pointer<Utf8>(Dart FFI提供的UTF-8编码指针,自带null结尾)
  • 创建一个指针数组(Pointer<Pointer<Utf8>>),长度为参数数量+1(最后补NULL)
  • 把每个Pointer<Utf8>赋值到数组对应的位置,最后一个位置设为nullptr
  • 调用C函数时传入参数数量和这个指针数组,用完后记得释放所有分配的内存,避免泄漏

修正后的完整代码

import 'dart:ffi';
import 'dart:io';
import 'package:ffi/ffi.dart';

// 修正C函数的FFI签名:argv的类型是Pointer<Pointer<Utf8>>,对应C的char** argv
typedef benchmark_hexagon_main_test = Int32 Function(Int32 argc, Pointer<Pointer<Utf8>> argv);
// Dart对应的函数类型
typedef benchmarkHexagonMainTest = int Function(int argc, Pointer<Pointer<Utf8>> argv);

static Future<RunTime> benchmarkMainTest(String f, int P, int l) async {
  final DynamicLibrary libBenchmark = Platform.isAndroid 
      ? DynamicLibrary.open("libbenchmark.so") 
      : DynamicLibrary.process();
  
  final benchmarkHexagonMainTest hexagonBenchmark = libBenchmark
      .lookup<NativeFunction<benchmark_hexagon_main_test>>("benchmark_test_main_start")
      .asFunction();

  // 1. 整理所有命令行参数为字符串列表
  final List<String> args = [
    "Program",
    "-f",
    f,
    "-P",
    "$P",
    "-l",
    "$l",
  ];
  final int argc = args.length;

  // 2. 转换每个字符串为Utf8指针,存入临时列表
  final List<Pointer<Utf8>> argPointers = args.map((str) => str.toNativeUtf8()).toList();

  // 3. 分配指针数组,长度为argc + 1(最后加NULL标记结束)
  final Pointer<Pointer<Utf8>> argv = calloc<Pointer<Utf8>>(argc + 1);

  // 4. 填充指针数组
  for (int i = 0; i < argc; i++) {
    argv[i] = argPointers[i];
  }
  // 最后一个元素必须设为NULL
  argv[argc] = nullptr;

  try {
    // 调用C函数,传入正确的argc和argv
    hexagonBenchmark(argc, argv);
  } finally {
    // 5. 释放所有分配的内存,避免泄漏
    calloc.free(argv);
    for (final ptr in argPointers) {
      calloc.free(ptr);
    }
  }

  // 这里补充你的RunTime返回逻辑,原代码未实现,请自行完善
  return RunTime(...);
}

关键修改说明

  1. 修正了FFI签名:把argv的类型从Pointer<Utf8>改为Pointer<Pointer<Utf8>>,这才符合C语言中char *argv[](等价于char **argv)的类型定义。
  2. 模拟C的argv结构:不再尝试构造带空字符的单一字符串,而是用指针数组完全复刻C环境下的argv格式。
  3. 增加内存管理:在finally块中释放所有通过calloc分配的内存,这在FFI调用中是必须的,否则会造成内存泄漏。

内容的提问来源于stack exchange,提问作者Vikram Kapoor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 14:07:53