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

C#调用C++ DLL时嵌套结构与联合体的字符串传递问题

解决C#调用C++ DLL时嵌套联合体结构体的字符串传递问题

问题根源

  1. 联合体内存偏移错误:C++的union所有成员共享同一块起始内存,但你在C#的pdll_test_data中给sensor字段设置了FieldOffset(4),导致结构体内存布局完全错位,后续的字符串成员自然无法正确映射。
  2. bool类型封送不匹配:C#默认会把bool封送为4字节的UnmanagedType.Bool,但C++中的bool是1字节,类型大小不匹配会导致后续成员的内存偏移全部错乱。
  3. 结构体对齐差异:C#和C++编译器的默认内存对齐规则可能不同,未显式指定会引发内存布局偏差。

修正后的C#代码

using System;
using System.Runtime.InteropServices;

namespace CSharpApp
{
    public class Program
    {
        public enum pdll_test_id
        {
            dut_com_init = 0,
            cont_pkt_tx = 1,
        };

        // 显式指定对齐方式为1,匹配C++默认对齐(或根据实际编译器调整)
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct pdll_sensor_test
        {
            public pdll_test_id test_id;
            // 显式指定封送为1字节的bool,匹配C++的bool类型
            [MarshalAs(UnmanagedType.U1)]
            public bool en;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 13)]
            public string name;
            public int reg_addr;
        };

        // 联合体所有成员共享偏移0的内存
        [StructLayout(LayoutKind.Explicit, Pack = 1)]
        public struct pdll_test_data
        {
            [FieldOffset(0)]
            public pdll_test_id id;
            [FieldOffset(0)]
            public pdll_sensor_test sensor;
        };

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct pdll_device
        {
            [MarshalAs(UnmanagedType.U1)]
            public bool is_active;
            public pdll_test_data test;
        };

        [DllImport("CPPDynamicDLL.dll")]
        public static extern int PdllDeviceMethod(ref pdll_device pdlldevice);

        public static void Main(string[] args)
        {
            Console.WriteLine("This is C# program");
            pdll_device pdllDevice = new pdll_device();
            pdllDevice.is_active = true;
            // 注意:联合体成员互斥,设置sensor后id的值会被覆盖,按需调整赋值逻辑
            pdllDevice.test.sensor.test_id = pdll_test_id.cont_pkt_tx;
            pdllDevice.test.sensor.en = true;
            pdllDevice.test.sensor.name = "wsa";
            pdllDevice.test.sensor.reg_addr = 1024;
            var result = PdllDeviceMethod(ref pdllDevice);
        }
    }
}

关键修改说明

  • 联合体FieldOffset修正:将pdll_test_data中sensor的FieldOffset改为0,和id共享同一块内存,符合C++ union的内存布局规则。
  • bool类型封送指定:给所有bool字段添加[MarshalAs(UnmanagedType.U1)],确保封送为1字节,和C++的bool大小一致。
  • 结构体对齐设置:给所有结构体添加Pack=1,强制按1字节对齐,避免因编译器默认对齐规则不同导致的内存偏移问题。
  • 联合体成员赋值注意:C++ union的成员互斥,赋值一个成员会覆盖另一个,代码中移除了对id的冗余赋值(会被sensor覆盖),可根据实际业务逻辑调整。

测试效果

修改后重新编译C#程序和C++ DLL,调用时C++端的printf会正确输出pdlldevice->test.sensor.name=wsa,其他字段也能正常映射。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 05:43:14