将C#int数组传递给C ++

时间:2016-08-01 18:48:08

标签: c# arrays c++-cli

所以我将我在C#中创建的数组传递给函数:

options = new int[3];
options[0] = 3;
options[1] = 5;
options[2] = 4;
formatvalue(options);// the function header is: formatvalue(object options)

从这里开始,它通过一些接口,最终在一个c ++项目中结束。

在c ++中,函数头看起来像: formatvalue(System::Object^ value)

在c ++函数中,我只想读取数据。传递数组的全部意义在于,我不必为函数提供大量不同的参数。这花了一些时间来弄清楚除了变量以外的任何东西都给了我一些非常奇怪的值。起初我试图传递一个int结构,但是在编译时将System :: Object转换成任何东西都很困难。最后我最终得到了一些有用的c ++代码:

int* test;
memcpy(&test, &value, sizeof(value));
int x;
for (int i = 0; i < 16; i++)
{
    x = *(test + i);
}

奇怪的是,当我取消引用测试时,它给了我一些奇怪的垃圾,直到我到达*(test + 4)我的数组开始的地方:D。这是内存的样子:

f8 ae 0b c2 fe 7f 00 00 03 00 00 00 00(阵列从这里开始)00 00 00 03 00 00 00 05 00 00 00 04

我认为地址测试指向应该是数组中的第一个值,而不是在我的数组实际开始之前有13个字节的垃圾。有人告诉我这13个字节可能是dope vector?这是有道理的,因为我的数组的长度是3,并且在前13个字节中有一个随机的3坐在那里。

所以问题:

  1. 为什么test的地址不是数组的开头?
  2. 前13个字节是涂料矢量吗?
  3. 我对指针/ memcpy的使用是否正确?
  4. 编辑1:更改了第一个问题。

1 个答案:

答案 0 :(得分:1)

我建议您阅读一本关于C ++ / CLI的书或一些文章,因为您希望对托管和非托管代码和内存的行为方式有一个相当好的理解。

它不是一个涂料矢量,并且开头的数据不是垃圾(没有它你的程序就无法运行!)。

数组的起始实际上是16个字节而不是13个字节(参见内存对齐)。请注意,内存在您的计算机上以little-endian存储,因此3将存储为#include<stdio.h> #include<stdlib.h> struct node{ int data; struct node* prev; struct node* next; }; void insert_beg(struct node** head, int new_data){ struct node* temp = (struct node*)malloc(sizeof(struct node)); temp->data = new_data; if(*head == NULL){ temp->next = *head; temp->prev = NULL; *head = temp; } else{ temp->next = *head; (*head)->prev = temp; *head = temp; } } void insert_before(struct node* next_node,int new_data){ struct node* temp = (struct node*)malloc(sizeof(struct node)); temp->data = new_data; if(next_node == NULL) printf("Invalid!!!!"); temp->prev = next_node->prev; temp->next = next_node; next_node->prev = temp; if(temp->prev!=NULL) temp->prev->next = temp; } void printList(struct node* head){ if(head == NULL) printf("The list is empty\n"); else { while(head!=NULL){ printf("%d\n",head->data); head = head->next; } } } int main(){ struct node* head = NULL; printList(head); insert_beg(&head,10); insert_beg(&head,20); insert_before(head,70); insert_beg(&head,30); printList(head); } 而不是03 00 00 00

根据您提供的内存,看起来您正在初始化00 00 00 03作为C#数组的地址。 .NET通过方法表指针跟踪信息类型信息的额外开销。数组还有一个字段,用于存储数组中元素的数量。在这种情况下:

int* test

你想要做的是与此类似的事情:

f8 ae 0b c2 fe 7f 00 00 <- Method table pointer (7ffec20baef8)
03 00 00 00 <- The number of elements in the array
00 00 00 00 <- Padding
03 00 00 00 05 00 00 00 04 00 00 00 <- Array data

获取数组中第一个元素的地址。您还必须使用array<int>^ arr = /* ... */; pin_ptr<int> ptr = &arr[0]; int* test = ptr; ,因为可能会发生GC并将数组移动到内存中的其他区域。

或者,您可以考虑使用P / Invoke而不是C ++ / CLI。使用P / Invoke时,CLR会自动处理固定并确保将指向数组和其他类型的指针正确地传递给本机方法。

编辑:我忘了问题3。

pin_ptr获取源指针,目标指针和要复制的总字节数(请注意,这与数组中的元素数不同)。如果memcpy是[{1}}的参数,那么value将与formatvalue相同。因此,如果源指针和目标指针是正确的,则只复制8个字节 - 数组的前两个元素。

但是,您的源和目标指针不正确。您已定义名为sizeof(value)的{​​{1}},但会将sizeof(void*)的地址传递给int*。您可能希望预先分配内存,将该内存的地址分配给test,然后将test的值传递给memcpy而不是引用。

这样的事情会起作用:

test