关于SDK接口中的指针问题

来源:互联网 发布:知豆汽车 编辑:程序博客网 时间:2024/05/24 07:34

关于SDK接口中的指针问题

 

 

黄延冬,2009.9.10

 

本文涉及到两个问题:

1. C#C++写的SDK传入指针时,指针内外不一样造成了无法正确访问相关变量

2. C#定义带有数组的结构体的问题

-------------------------------------------------------------------------------------------------------------------

今天和同事调试SDK的对外支持时发现的一个问题,原因是SDK接口中用到了指针。

SDK的接口中使用指针本身没有问题,但在有些情况下却会出现奇怪的现象。

 

SDK的接口中,用到了一个自定义结构的指针,在上层程序调用该接口时,把被初始化了的该结构指针传入SDK,在SDK中记录该指针。正常情况下,只要外部的该内存没有被破坏而且可访问,则SDK内部也可以正常使用该指针。这在C++调用此接口时没有发现问题,运行正常。但是今天和同事调试的时候,客户使用的是C#,在调用该接口时没有问题,但后续调用其它接口时,SDK内部使用到了该指针(之前记录在SDK中的),此时该指针已不能使用,其值已被改变,但在上层程序查看该内存,并没有发现什么不正常的情况。结果弄了半天,也没有弄明白,也不清楚原因。有望高手回复此贴。

 

在涉及到的结构中,定义了一个整型数据成员:int Value[16];

注:以下为C++中定义的数据结构

结构如下:

struct stu_test

{

long channel;

long index;

long datalength;

long reserved;

int value[16];

double dbset;

long lchang;

long lHeight;

};

 

SDK的接口定义如下:

void SetVSystemParam( unsigned long lHandle, stu_test *pStuTest );

void StartPlay( unsigned long lHandle );

 

下面只讨论C#调用时发生的情况,因为其它的大部分都用的是C++,它没有问题。

在调用SetVSystemParam()后,SDK的该接口实现函数中打印stu_test的值没有问题,都是对的,在SDK内部,会有一个变量stu_test *m_pStuTest;记录传入的pStuTest的指针,在StartPlay()接口中会用到m_pStuTest;,但在这个接口中发现此指针的值已经不对,完全变样了,但是这个指针是没有变化的(已经排除了这种低级错误),即指向的确是同一块内存,但是其值不一样,在调用StartPlay()接口时,上层保存该结构的变量依然有效,而且其值也没有任何改变。这就奇怪了。

后来又发现一个问题,在上层中,使用VC的内存查看,发现上层保存的变量地址(记为MA)和SDK中记录的该指针(记为MS)是不一样的!

 

而且对于C#中结构的定义,和C++中也不大相同,特别是对于涉及到的数组int value[16];的定义更是完全不一样。开始的时候,上层定义为:

int[] value;

结果在sizeof()打印结构的大小时,显示是不正确的,该成员是被当成一个指针,只占用了4个字节,后来改成在它的前面增加占用了16int的空间([MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]

),后面再定义int[] value;,最后的结构大致如下:

public struct stu_test

{

int  channel;

int  index;

int  datalength;

int  reserved;

MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)

int[] value;

double dbset;

int  lchang;

int  lHeight;

};

虽然使用sizeof()查看其占用的内存大小没错,但是其内容还是不正确的,通过内存查看,发现结构和内存根本对不上。在内存中,前面的4个字节应该是channel占用的,但实际上,整个数据是从开始内存的位置向后偏移大概是12个字节的位置开始的,而且在value的内存位置,根本不是value的值,反倒其后面的成员dbset等等的值跑到了value的前面!在初始化结构时,对value是进行了new操作,即分配了内存。在查看value的内存时,它的位置显然不在stu_test结构体所占用的内存范围内!所以这样定义还是不对,即使是结构体的内存大小没错!

后来实在没办法,就把int value[16];拆开成16个成员变量进行了定义,这次再查看内存没有错了,都对得上了。注意:这只是内存对得上,该问题和前面调用SDKSDK内部的内存值不对没有关系。

 

问题1的解决方法是修改SDK。在SDK内部自己分配内存,然后在SetVSystemParam()中把外部传入的内存值拷贝到SDK自己的内存地址中。这样,外面再调用StartPlay()时就没有问题了。但这只是其中的一个解决方法,而且可能不能适用于所有的情况。

 

请各位发表高见,我只熟悉C++,不熟悉C#,没有用过。

原创粉丝点击