2015-11-02 23 views
8

câu hỏi này được đề cập đến 'mới' D: DMD32 D Compiler v2.068.2interfacing với D đúng trả về một mảng của Struct

cho TL; DR nếu bạn không cần phải chi tiết skip cho câu hỏi dưới đây

làm việc với visual studio (tôi đang sử dụng v2010), bằng cách tạo ra một new project ->D ->Dynamic Library

khi quá trình creartion dự án hoàn tất, trong cửa sổ solution explorer có 2 file:

  • dllmain.d
  • dll.def

bỏ tập tin .def như nó có, tôi đã được quản lý để hiểu rằng bằng cách thêm một số chức năng mới vào dllmain.d và prefexing với:

extern (Windows) export 

sẽ xuất các chức năng và nó sẽ được gọi từ c#, đã không thử nó với C hoặc C++.

lưu ý phụ, không chạm vào bất kỳ mã hiện có nào trừ khi bạn biết mình đang làm gì.

để mã dưới đây làm việc như mong đợi

extern (Windows) export uint D_mathPower(uint p) 
{  
    return p * p; 
} 

gọi nó từ C# với các chữ ký sau:

[DllImport(@"pathTo...\DynamicLib1.dll", CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurity] 
    public static extern uint D_mathPower(uint p); 

tôi dễ dàng có thể sử dụng nó như sau:

uint powD = D_mathPower(5); 

câu hỏi của tôi là

làm cách nào để tôi trả lại một mảng cấu trúc (tốt nhất là cách tiết kiệm chi phí nhất)?

struct dpack{ char* Name; uint Id; } 

tôi đã thử sử dụng cả hai char[]char* nhưng không thành công.

đây là mã của tôi cho đến nay

extern (Windows) export 
dpack[] D_getPacks(uint size) 
{ 
    dpack[] rtDpArr = new dpack[size]; 
    char[] str = "someText".dup; 

    for(uint i=0; i<size; i++) 
    { 

     str[$ - 1] = cast(char)('0' + i % (126 - '0')); 
     rtDpArr[i].Id = i; 
     rtDpArr[i].Name= str.dup; 
    } 
    return rtDpArr; 
} 


void getPacksPtr(uint size, dpack** DpArr) 
{ 
// this is the signature i have successfully implemented via c++ 
} 
+0

trở về mảng D để một ngôn ngữ có thể làm việc nhưng thường không vì các chi tiết ABI sẽ không nhất thiết phải phù hợp. Hãy thử tạo kiểu struct của riêng bạn với con trỏ và chiều dài cho interop hoặc làm một cái gì đó như 'getArray (size_t * lengthPtr, dpack ** ptrPtr) {* lengthPtr = array.length; * ptrPtr = array.ptr; } ' –

+0

Bạn nên thực hành tạo một DLL C và sử dụng nó trong C# trước khi thử nó với một D DLL. Tìm hiểu cách sử dụng các hàm C trả về "mảng" từ C#, sau đó sử dụng kỹ thuật tương tự trong D. C# không có kiến ​​thức về cách D lưu trữ lát, vì vậy bạn sẽ không thể sử dụng chúng như là. –

Trả lời

1

Bởi vì một mảng D có một bố cục đặc biệt bạn thay vì phải trả lại một con trỏ đến mục đầu tiên. Sau đó, trong C# bạn có thể cast mỗi mục từ con trỏ cơ sở bằng cách đọc 8 byte cho mỗi 8 byte (điều này phù hợp với dpack.sizeof), vì bạn đã biết đếm:

struct dpack{ immutable(char)* Name; uint Id; } 

extern (Windows) export 
void* D_getPacks(uint count) 
{ 
    dpack[] rtDpArr = new dpack[count]; 
    char[] str = "someText".dup; 

    import std.string; 
    for(uint i=0; i<count; i++) 
    { 
     rtDpArr[i].Id = i; 
     // add a trailing '\0' 
     rtDpArr[i].Name = toStringz(str); 
    } 
    // pointer to the first item 
    return rtDpArr.ptr; 
} 

Ngoài ra để đúc thành viên .Name đó là cần thiết để thêm một terminator, nếu không bạn không thể biết chiều dài của chuỗi.Điều này được thực hiện bởi std.string.toStringz sẽ thêm một ký tự null vào cuối chuỗi. Các thành viên char* Name sau đó có thể được đúc như là thường được cung cấp bởi một chức năng trong một dll với một giao diện C.

+0

hey cảm ơn @Nested loại ..cho mã, tôi đã thử nghiệm rất nhiều biến thể nhưng không bao gồm 'std.string' tôi đã thử mã của bạn sau khi tôi allready tìm thấy một câu trả lời và sau khi benchmarking chống lại' C++ 'thực hiện, tôi sau đó thử nghiệm với 'std.string' và hiệu suất đã được giảm xuống 0,75% so với trường' char * '. và như là mã nhanh nhất trong D (cho đến nay) đó là những gì tôi đã đăng .. nó vẫn còn chậm hơn so với aproach nhanh nhất trong C++ cũng là 0,75% của 'C++' code vì vậy C++ là 45 ms,' D (char *) 'là 57 ms, và' D (std.string) 'là 79 ms. –

+0

Điều lạ lùng là mỗi khi tôi gọi hàm này, nội dung khác đuôi ở phần tử [0] một lần có thể là 'G' sau đó thực hiện lại nó là'; 'thì lại' G 'lại không ổn định, nó có gì không để làm với 'malloc' mà không có' free' hoặc nó có thể là gì? –

0

đây là cách hiệu quả nhất mà tôi có thể triển khai.

extern (Windows) export 
void D_getPacksPtr(uint size, dpack** DpArr) 
{ 
    *DpArr = cast(dpack*) malloc(size * dpack.sizeof); 
    dpack* curP = *DpArr; 
    char[] str = "abcdefghij".dup; 
    uint i=0; 
    while(i!=size){ 
     str[$ - 1] = cast(char)('0' + i % (126 - '0')); 
     curP.Name = cast(char*)str.dup; curP.Id = i; 
     ++i;++curP; 
    } 
} 

    [DllImport(@"PathTo...\DynamicLib1.dll", CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurity] 
    public static extern void D_getPacksPtr(uint size, dpack** DPArr); 

sử dụng nó:

dpack* outDpack; 
    D_getPacksPtr(500000, &outDpack); 
Các vấn đề liên quan