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

使用DART FFI调用C++函数返回结果每次执行不一致的原因

动态库返回指针导致结果不一致的问题分析与修复

编译通过但重复运行返回结果不一致:当length=20时连续10次结果一致,length=5时每次运行结果不同。

问题代码

C++ 代码

#include <vector>
#include <iostream>

extern "C" int* get_int_array(int size);

int* get_int_array(int size) {
        
        std::vector<int> vec(size);
        for (int i = 0; i < size; i++) {
            vec[i] = i;
        }
        int* arr = vec.data();
        
        std::cout << "C++ Result" << std::endl;
        for (int i =0; i< size; i++)
        {
            std::cout << arr[i] << ",";
        }
        std::cout << std::endl;
        
        return arr;
}

// 编译命令:g++ -shared -lstdc++ -o user_func.dll user_func.cpp -Wl,--output-def,user_func.def,--out-implib,libuser_func.a

Dart 代码

import 'dart:ffi';

void main() {
  final path = './user_func.dll';
  final _lib = DynamicLibrary.open(path);

  // int* get_int_array(int size)
  final getIntPtr = _lib.lookupFunction<Pointer<Int32> Function(Int32),
      Pointer<Int32> Function(int)>('get_int_array');

  final length = 5;
  final ptr = getIntPtr(length);
  final array = ptr.asTypedList(length);
  print('\nDart Result');
  print(ptr);
  print(array);
}

问题根源

核心问题是悬空指针:C++函数中的std::vector<int> vec是局部变量,函数执行完毕返回时,vec会被销毁,其内部管理的堆内存会被释放。此时返回的vec.data()指针变成悬空指针,指向的内存已不属于程序有效内存。

后续Dart访问这块内存时,内存可能已被其他操作覆盖(比如栈帧复用、堆内存重新分配),导致结果随机。length=20时看似稳定,只是这块内存暂时未被覆盖,属于未定义行为的偶然表现,本质仍然错误。

修复方案

方案1:C++动态分配内存,Dart主动释放

在C++中用new[]动态分配数组,返回指针,同时提供释放函数让Dart调用,避免内存泄漏。

修改后的C++代码:

#include <iostream>

extern "C" int* get_int_array(int size);
extern "C" void free_int_array(int* arr);

int* get_int_array(int size) {
    int* arr = new int[size];
    for (int i = 0; i < size; i++) {
        arr[i] = i;
    }
    
    std::cout << "C++ Result" << std::endl;
    for (int i =0; i< size; i++)
    {
        std::cout << arr[i] << ",";
    }
    std::cout << std::endl;
    
    return arr;
}

void free_int_array(int* arr) {
    delete[] arr;
}

修改后的Dart代码:

import 'dart:ffi';

void main() {
  final path = './user_func.dll';
  final _lib = DynamicLibrary.open(path);

  // int* get_int_array(int size)
  final getIntPtr = _lib.lookupFunction<Pointer<Int32> Function(Int32),
      Pointer<Int32> Function(int)>('get_int_array');
  
  // void free_int_array(int* arr)
  final freeIntArray = _lib.lookupFunction<Void Function(Pointer<Int32>),
      void Function(Pointer<Int32>)>('free_int_array');

  final length = 5;
  final ptr = getIntPtr(length);
  final array = ptr.asTypedList(length);
  print('\nDart Result');
  print(ptr);
  print(array);
  
  // 释放动态分配的内存,避免泄漏
  freeIntArray(ptr);
}

方案2:Dart分配内存,C++填充数据

由Dart负责内存分配,将内存指针传递给C函数,C直接填充数据。这种方式无需手动释放内存,内存由Dart的GC管理。

修改后的C++代码:

#include <iostream>

extern "C" void fill_int_array(int* arr, int size);

void fill_int_array(int* arr, int size) {
    for (int i = 0; i < size; i++) {
        arr[i] = i;
    }
    
    std::cout << "C++ Result" << std::endl;
    for (int i =0; i< size; i++)
    {
        std::cout << arr[i] << ",";
    }
    std::cout << std::endl;
}

修改后的Dart代码:

import 'dart:ffi';
import 'dart:typed_data';

void main() {
  final path = './user_func.dll';
  final _lib = DynamicLibrary.open(path);

  // void fill_int_array(int* arr, int size)
  final fillIntArray = _lib.lookupFunction<Void Function(Pointer<Int32>, Int32),
      void Function(Pointer<Int32>, int)>('fill_int_array');

  final length = 5;
  final array = Int32List(length);
  fillIntArray(array.dataAsPointer(), length);
  
  print('\nDart Result');
  print(array);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 22:22:48