积极答复者
非托管C++中的结构体数组指针在CLI中如何调用

问题
答案
-
1. fnStaticLibStructTest这个函数是不是你自己写的,这个函数是完全是错误的,应该不是类库里现有的东西,否则类库就是错误的,应该联系作者。
2. c++ cli还是c++,指针方面没有托管不托管的区别。
例如:#include "stdafx.h" #include "malloc.h" #pragma unmanaged struct untestStru { int ua; double ub; }; void fnStaticLibStructTest(untestStru** teststr, int *num) { if (teststr == nullptr) { return; } int n = 5; auto str = new untestStru[n]; for (int i = 0; i < n; i++) { str[i].ua = i * 5; str[i].ub = (i + 20.0); } *teststr = str; *num = n; } #pragma managed //以上部分模拟标准c++,以下部分为c++ cli内容。 using namespace System; ref struct CLITestStru { int a; double b; }; int main(array<System::String ^> ^args) { int nnn; untestStru* ptStru; fnStaticLibStructTest(&ptStru, &nnn); auto cliTestStruct = gcnew array<CLITestStru^>(nnn); for (int i = 0; i != nnn; ++i) { cliTestStruct[i] = gcnew CLITestStru(); cliTestStruct[i]->a = ptStru[i].ua; cliTestStruct[i]->b = ptStru[i].ub; Console::WriteLine(cliTestStruct[i]->a); Console::WriteLine(cliTestStruct[i]->b); } delete[] ptStru; return 0; }
-
bug 1 :fnStaticLibStructTest完全没有使用参数teststr的值
bug 2:CLI中代码假定abc的大小是5个untestStru(实际上是1个,fnStaticLibStructTest函数里给参数赋值只影响函数内那个参数副本,函数执行完那个参数的值就被丢弃了)
你的函数参数是传值的。如果你要从函数参数输出一个指针,你的函数的类型应该是指针的引用或者指针。
你也可以在函数外部分配传结构体数组的内存,前提是你已经知道数组大小。
Visual C++ MVP- 已编辑 Sheng Jiang 蒋晟Moderator 2019年4月23日 13:02
- 已建议为答案 mingxyzonline 2019年4月24日 5:23
- 已标记为答案 zjyh16 2019年4月24日 9:13
-
1. 如果是提前分配好的,那参数应该是const int num,而不是int* num。已经确定好个数了,不需要也不应该再回写。
2. 【*teststr = str;】不能这样写是因为teststr是数组,不是一个单一的值,数组本身就是用指针类型描述的,指向数组的首地址,因此数组的指针就等于指针的指针,所以也就不存在【teststr = &str;】这样的写法。详细内容还是需要阅读教程,教程中会有关于数组的详细介绍,论坛上不可能全篇摘录。
3. 至于更加妥当的写法吗,这个没办法谈啊。因为不知道你写这段代码的目的是什么?学习练习?解决某种问题?不知道目的也就没法说如何才“更妥当”。总体上说一般纯c++代码(包括c++ cli)肯定不会这么写,这种写法更多是为了兼容c语言。另外如果你用的是c++ cli,按说根本就不需要这么折腾啊,AllocHGlobal和FreeHGlobal一般都是在c#、vb里面才需要用,你这里是为了测试吗,或是在练习?总的来说就是你目前的代码是正确的,但如果是真实项目肯定不应该这么写,如果是做练习那就没问题。
补充一点:上面代码里面少了一句。
auto str = new untestStru[n];
这里分配了内存,在fnStaticLibTest函数结束前必须用delete[] str;来释放,不然就泄漏了。
全部回复
-
你好,
感谢您在MSDN论坛发帖提问。
>>在CLI中该如何才能调用这个结构体数组,获取或修改该数组结构体中的成员?
我建议你可以参考以下链接:https://github.com/langyastudio/cli
https://blog.csdn.net/aoshilang2249/article/details/42319423Best Wishes,
Jeanine Zhang -
你好,
感谢您在MSDN论坛发帖提问。
>>在CLI中该如何才能调用这个结构体数组,获取或修改该数组结构体中的成员?
我建议你可以参考以下链接:https://github.com/langyastudio/cli
https://blog.csdn.net/aoshilang2249/article/details/42319423Best Wishes,
Jeanine Zhang尝试按照链接中的去做,结果失败了。感觉和我想要的有点不一样,我是想获得非托管输出的结构体数组,示例更像是传入结构体数组。
我的代码,不明白问题出在哪?请指教:
非托管C++:
void fnStaticLibStructTest(untestStru *teststr, int *num) { if (teststr == nullptr) { return; } int n = 5; teststr = (untestStru*)calloc(n, sizeof(teststr)); for (int i = 0; i < n; i++) { teststr[i].ua = i * 5; teststr[i].ub = (i + 20.0); } *num = n; }
CLI中代码:
untestStru abc; int nnn; fnStaticLibStructTest(&abc, &nnn); cliTestStruct = gcnew array<CLITestStru^>(nnn); untestStru* ptStru = static_cast<untestStru*>(IntPtr(&abc).ToPointer()); for (int i = 0; i < nnn; i++) { cliTestStruct[i]->a = ptStru[i].ua; cliTestStruct[i]->b = ptStru[i].ub; Console::WriteLine(cliTestStruct[i]->a); Console::WriteLine(cliTestStruct[i]->b); }
查询其他资料做了尝试还是没能搞定,C++初学者寻求帮助。谢谢!
努力~
-
1. fnStaticLibStructTest这个函数是不是你自己写的,这个函数是完全是错误的,应该不是类库里现有的东西,否则类库就是错误的,应该联系作者。
2. c++ cli还是c++,指针方面没有托管不托管的区别。
例如:#include "stdafx.h" #include "malloc.h" #pragma unmanaged struct untestStru { int ua; double ub; }; void fnStaticLibStructTest(untestStru** teststr, int *num) { if (teststr == nullptr) { return; } int n = 5; auto str = new untestStru[n]; for (int i = 0; i < n; i++) { str[i].ua = i * 5; str[i].ub = (i + 20.0); } *teststr = str; *num = n; } #pragma managed //以上部分模拟标准c++,以下部分为c++ cli内容。 using namespace System; ref struct CLITestStru { int a; double b; }; int main(array<System::String ^> ^args) { int nnn; untestStru* ptStru; fnStaticLibStructTest(&ptStru, &nnn); auto cliTestStruct = gcnew array<CLITestStru^>(nnn); for (int i = 0; i != nnn; ++i) { cliTestStruct[i] = gcnew CLITestStru(); cliTestStruct[i]->a = ptStru[i].ua; cliTestStruct[i]->b = ptStru[i].ub; Console::WriteLine(cliTestStruct[i]->a); Console::WriteLine(cliTestStruct[i]->b); } delete[] ptStru; return 0; }
-
bug 1 :fnStaticLibStructTest完全没有使用参数teststr的值
bug 2:CLI中代码假定abc的大小是5个untestStru(实际上是1个,fnStaticLibStructTest函数里给参数赋值只影响函数内那个参数副本,函数执行完那个参数的值就被丢弃了)
你的函数参数是传值的。如果你要从函数参数输出一个指针,你的函数的类型应该是指针的引用或者指针。
你也可以在函数外部分配传结构体数组的内存,前提是你已经知道数组大小。
Visual C++ MVP- 已编辑 Sheng Jiang 蒋晟Moderator 2019年4月23日 13:02
- 已建议为答案 mingxyzonline 2019年4月24日 5:23
- 已标记为答案 zjyh16 2019年4月24日 9:13
-
bug 1 :fnStaticLibStructTest完全没有使用参数teststr的值
bug 2:CLI中代码假定abc的大小是5个untestStru(实际上是1个,fnStaticLibStructTest函数里给参数赋值只影响函数内那个参数副本,函数执行完那个参数的值就被丢弃了)
你的函数参数是传值的。如果你要从函数参数输出一个指针,你的函数的类型应该是指针的引用或者指针。
你也可以在函数外部分配传结构体数组的内存,前提是你已经知道数组大小。
Visual C++ MVP
-
bug 1 :fnStaticLibStructTest完全没有使用参数teststr的值
bug 2:CLI中代码假定abc的大小是5个untestStru(实际上是1个,fnStaticLibStructTest函数里给参数赋值只影响函数内那个参数副本,函数执行完那个参数的值就被丢弃了)
你的函数参数是传值的。如果你要从函数参数输出一个指针,你的函数的类型应该是指针的引用或者指针。
你也可以在函数外部分配传结构体数组的内存,前提是你已经知道数组大小。
Visual C++ MVP
应该还有一个bug 3,用calloc分配了非托管内存后没有free,因此内存泄漏。努力~
-
传指针的指针**就是为了回写,如果在cli里分配内存则可以传*,但是就不能在c++里面用new再次分配了。不传**,传指针的引用(*&)也是可以的,但是这个不兼容c语言,只能给c++用,因此大部分类库都用**,这样可以与c语言兼容。一般只有在c++当前项目或静态库里面才用*&。
上面我的示例代码和我与“Sheng Jiang蒋晟”谈论的就是【要传指针且不知道大小内部模拟函数来确定大小】这个问题啊。
嗯,这里基本理解了,谢谢!自学中还有个困惑请教一下,假设已知要传的指针大小的情况,那我下面这段代码是否正确?有更加妥当的写法吗?还有个问题就是如注释中写的那样,为何不能直接去str的地址给teststr?
typedef struct _untestStru { int ua = 0; float ub = 0; }untestStru; void fnStaticLibTest(untestStru *teststr, int *num) { if (teststr == nullptr) { return; } int n = 5; auto str = new untestStru[n]; for (int i = 0; i < n; i++) { str[i].ua = i * 5; str[i].ub = (i + 20.0); } for (int i = 0; i < n; i++) { teststr[i] = str[i]; } //*teststr = str;//为何不能这样写? //teststr = &str;//为何不能这样写? *num = n;//这里却是可以,两者有什么区别? } //以上部分模拟标准c++,以下部分为c++ cli内容。 ref struct CLITestStru { int a; double b; }; int main(array<System::String^>^ args) { int nnn = 5; IntPtr pt = Marshal::AllocHGlobal(nnn * Marshal::SizeOf(untestStru::typeid)); untestStru* ptStru = static_cast<untestStru*>(pt.ToPointer()); fnStaticLibTest(ptStru, &nnn); auto cliTestStruct = gcnew array<CLITestStru^>(nnn); for (int i = 0; i != nnn; ++i) { cliTestStruct[i] = gcnew CLITestStru(); cliTestStruct[i]->a = ptStru[i].ua; cliTestStruct[i]->b = ptStru[i].ub; Console::WriteLine(cliTestStruct[i]->a); Console::WriteLine(cliTestStruct[i]->b); } Marshal::FreeHGlobal(pt); //delete[] ptStru; return 0; }
努力~
- 已编辑 zjyh16 2019年4月24日 7:07
-
1. 如果是提前分配好的,那参数应该是const int num,而不是int* num。已经确定好个数了,不需要也不应该再回写。
2. 【*teststr = str;】不能这样写是因为teststr是数组,不是一个单一的值,数组本身就是用指针类型描述的,指向数组的首地址,因此数组的指针就等于指针的指针,所以也就不存在【teststr = &str;】这样的写法。详细内容还是需要阅读教程,教程中会有关于数组的详细介绍,论坛上不可能全篇摘录。
3. 至于更加妥当的写法吗,这个没办法谈啊。因为不知道你写这段代码的目的是什么?学习练习?解决某种问题?不知道目的也就没法说如何才“更妥当”。总体上说一般纯c++代码(包括c++ cli)肯定不会这么写,这种写法更多是为了兼容c语言。另外如果你用的是c++ cli,按说根本就不需要这么折腾啊,AllocHGlobal和FreeHGlobal一般都是在c#、vb里面才需要用,你这里是为了测试吗,或是在练习?总的来说就是你目前的代码是正确的,但如果是真实项目肯定不应该这么写,如果是做练习那就没问题。
补充一点:上面代码里面少了一句。
auto str = new untestStru[n];
这里分配了内存,在fnStaticLibTest函数结束前必须用delete[] str;来释放,不然就泄漏了。