Defining variable length structs and casting to them

In C, you sometimes see something like: struct foobar { int size; int data[1]; }; where the `data` member doesn't really have just one element; rather it's meant to be variable length. If you do something like that in D, is it going to let you, for example, read `[4]`? I know D has variable length arrays, e.g. `int[] myvarlenintarray;`, but what if you're trying to interface with some code that already puts out a data structure in memory like the one above, and possibly much more complex than that? Let's say it's in the first portion of `int[3000] buffer;`. Is there an easy way to cast it to a usable struct without moving it in memory? If not, is there an easy way to get the data into a similar struct without having to manually parse out each member of the struct? edit: I think I need to give a practical example so you see where I'm coming from. import; import std.utf; import std.stdio; public struct REPARSE_DATA_BUFFER { ULONG ReparseTag; USHORT ReparseDataLength; USHORT Reserved; union { struct SymbolicLinkReparseBuffer { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; ULONG Flags; WCHAR[1] PathBuffer; } SymbolicLinkReparseBuffer mySymbolicLinkReparseBuffer; struct MountPointReparseBuffer { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; WCHAR[1] PathBuffer; } MountPointReparseBuffer myMountPointReparseBuffer; struct GenericReparseBuffer { UCHAR[1] DataBuffer; } GenericReparseBuffer myGenericReparseBuffer; } } alias REPARSE_DATA_BUFFER* PREPARSE_DATA_BUFFER; enum MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16*1024; // Values for 'ReparseTag' member of REPARSE_DATA_BUFFER: enum : DWORD { IO_REPARSE_TAG_SYMLINK = 0xA000000C, IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003 // which also defines a Junction Point } enum DWORD FSCTL_GET_REPARSE_POINT = 0x000900a8; enum FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000; public extern(Windows) BOOL function(HANDLE, DWORD, LPVOID, DWORD, LPVOID, DWORD, LPVOID, OVERLAPPED*) DeviceIoControl; void main() { DeviceIoControl = cast(BOOL function(HANDLE, DWORD, LPVOID, DWORD, LPVOID, DWORD, LPVOID, OVERLAPPED*))GetProcAddress(LoadLibraryA("kernel32.dll"), "DeviceIoControl"); auto RPHandle = CreateFileW((r"J:\Documents and Settings").toUTF16z(), 0, FILE_SHARE_READ, null, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT + FILE_FLAG_BACKUP_SEMANTICS, null); if (RPHandle == INVALID_HANDLE_VALUE) { printf("CreateFileW failed with error code %d.", GetLastError()); return; } BYTE[MAXIMUM_REPARSE_DATA_BUFFER_SIZE] reparsebuffer; uint reparsedatasize; auto getreparsepointresult = DeviceIoControl(RPHandle, FSCTL_GET_REPARSE_POINT, null, 0, cast(void*) reparsebuffer.ptr, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &reparsedatasize, null); if (getreparsepointresult == 0) { printf("DeviceIoControl with FSCTL_GET_REPARSE_POINT failed with error code %d.", GetLastError()); return; } // Now what? // If I do this: auto ReparseDataPtr = cast(REPARSE_DATA_BUFFER*) reparsebuffer.ptr; printf("%d == %d\n", reparsebuffer.ptr, ReparseDataPtr); // Alright, data hasn't been copied. // But what good is a pointer? Can I use a pointer to a struct to access one of its members apart from dereferencing? printf("%d == %d\n", &reparsebuffer[0], &(*ReparseDataPtr)); // Here, I dereference ReparseDataPtr, but nothing moves. printf("%d == %d\n", &reparsebuffer[0], &((*ReparseDataPtr).ReparseTag)); // Same here, so I can access members in a roundabout way. printf("%d == %d\n", &reparsebuffer[0], &(ReparseDataPtr.ReparseTag)); // And thanks to Jim's comment, here's a less roundabout way. auto ReparseData = *ReparseDataPtr; // But if I assign a name to the dereferenced ReparseDataPtr, printf("%d != %d\n", &reparsebuffer[0], &(ReparseData.ReparseTag)); // the data is copied to a new location, leaving most of PathBuffer behind. REPARSE_DATA_BUFFER ReparseDataFn() {return *ReparseDataPtr;} // Similarly, this way printf("%d != %d\n", &reparsebuffer[0], &(ReparseDataFn().ReparseTag)); // copies stuff to a new location. } Firstly, I don't understand why it's different for the case in which I don't give `*ReparseDataPtr` a name. Secondly, is there no way to have a symbol whose type is REPARSE_DATA_BUFFER and whose data is located at reparsebuffer.ptr?

以上就是Defining variable length structs and casting to them的详细内容,更多请关注web前端其它相关文章!

赞(0) 打赏
未经允许不得转载:web前端首页 » Node.js答疑

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

前端开发相关广告投放 更专业 更精准