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

从C#调用C代码传递指针的正确性及异常解决问询

C#调用C代码传递指针引发内存访问异常的排查与解决

需求说明

需要从C#调用C代码,无需向C#暴露C的数据结构,仅传递指针即可。核心逻辑是C#决定操作流程,交由C执行后返回结果,C#无需了解C的具体实现细节。

初始实现代码

C代码

__declspec(dllexport) long cs_getB() {
    return &B;
}

__declspec(dllexport) int cs_order(long csa) {
    c_struct a = (c_struct *)csa;
    return order(a);
}

int order(c_struct a)
{
  // 具体实现
  return 0;
}

C#代码

[DllImport("C:\\whatever.dll", EntryPoint = "cs_getB", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr GetB();

[DllImport("C:\\whatever.dll", EntryPoint = "cs_order", CallingConvention = CallingConvention.StdCall)]
public static extern int Order(IntPtr a);

调用代码

IntPtr b = MyDll.GetB();
int bor = MyDll.Order(b);

遇到的问题

调用MyDll.Order时抛出异常:

System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'

更新信息

将C代码中的指针返回类型改为long long和intptr_t后,问题依旧。返回至C#的IntPtr值为0x00007ffef6de8750,且Visual Studio无法单步调试进入C代码。

更新后的相关C代码:

__declspec(dllexport) intptr_t getB() {
    return &B;
}

其中B的定义:

struct thingy {
  long* m729;
  ...
};
typedef struct thingy* thing;
thing B;

问题分析与解决方案

1. 调用约定不匹配

C代码默认使用cdecl调用约定,但C#的DllImport指定了StdCall,这会导致栈平衡错误,引发内存访问异常。需统一调用约定:

  • 方案一:C代码显式指定__stdcall
    __declspec(dllexport) intptr_t __stdcall getB() {
        return (intptr_t)&B;
    }
    
    __declspec(dllexport) int __stdcall cs_order(intptr_t csa) {
        thing a = (thing)csa;
        return order(a);
    }
    
  • 方案二:C#的DllImport改为CallingConvention.Cdecl
    [DllImport("C:\\whatever.dll", EntryPoint = "getB", CallingConvention = CallingConvention.Cdecl)]
    public static extern IntPtr GetB();
    
    [DllImport("C:\\whatever.dll", EntryPoint = "cs_order", CallingConvention = CallingConvention.Cdecl)]
    public static extern int Order(IntPtr a);
    

2. 指针类型转换与参数不匹配

C代码中order函数的参数是c_struct a(值传递结构体),但实际传递的是结构体指针,存在类型不匹配:

  • 如果order需要结构体值,需在cs_order中解引用指针:
    int cs_order(intptr_t csa) {
        thing ptr = (thing)csa;
        return order(*ptr); // 解引用指针得到结构体值
    }
    
  • 如果order需要指针,直接修改order的参数类型:
    int order(thing a) {
        // 实现逻辑
        return 0;
    }
    

3. 未初始化指针问题

检查B是否已正确初始化。thing B;仅声明了指针变量,未指向有效的结构体实例,访问其内存会触发错误。需确保B指向已分配的内存:

// 方式一:动态分配内存
thing B = (thing)malloc(sizeof(struct thingy));
// 方式二:指向全局结构体实例
struct thingy B_instance;
thing B = &B_instance;

4. 调试问题

确保C项目编译为调试版本,在Visual Studio中启用启用本机代码调试(项目属性→调试→启用本机代码调试),才能单步进入C代码调试。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 18:40:57