Search code examples
visual-c++wdk

What is the point of using arrays of one element in ddk structures?


Here is an excerpt from ntdddisk.h

typedef struct _DISK_GEOMETRY_EX {
        DISK_GEOMETRY Geometry;                                 // Standard disk geometry: may be faked by driver.
        LARGE_INTEGER DiskSize;                                 // Must always be correct
        UCHAR Data[1];                                                  // Partition, Detect info
} DISK_GEOMETRY_EX, *PDISK_GEOMETRY_EX;

What is the point of UCHAR Data[1];? Why not just UCHAR Data; ? And there are a lot of structures in DDK which have arrays of one element in declarations.

Thanks, thats clear now. The one thing is not clear the implementation of offsetof. It's defined as

#ifdef  _WIN64
#define offsetof(s,m)   (size_t)( (ptrdiff_t)&(((s *)0)->m) )
#else
#define offsetof(s,m)   (size_t)&(((s *)0)->m)
#endif

How this works: ((s *)0)->m ???

This

(size_t)&((DISK_GEOMETRY_EX *)0)->Data 

is like

sizeof (DISK_GEOMETRY) + sizeof( LARGE_INTEGER);

But there is two additional questions:

1) What type is this? And why we should use & for this?

((DISK_GEOMETRY_EX *)0)->Data

2) ((DISK_GEOMETRY_EX *)0)

This gives me 00000000. Is it convering to the address alignment? interpret it like an address?


Solution

  • Very common in the winapi as well, these are variable length structures. The array is always the last element in the structure and it always includes a field that indicates the actual array size. A bitmap for example is declared that way:

    typedef struct tagBITMAPINFO {
        BITMAPINFOHEADER    bmiHeader;
        RGBQUAD             bmiColors[1];
    } BITMAPINFO, FAR *LPBITMAPINFO, *PBITMAPINFO;
    

    The color table has a variable number of entries, 2 for a monochrome bitmap, 16 for a 4bpp and 256 for a 8bpp bitmap. Since the actual length of the structure varies, you cannot declare a variable of that type. The compiler won't reserve enough space for it. So you always need the free store to allocate it using code like this:

    #include <stddef.h>   // for offsetof() macro
    ....
    
        size_t len = offsetof(BITMAPINFO, bmiColors) + 256 * sizeof(RGBQUAD);
        BITMAPINFO* bmp = (BITMAPINFO*)malloc(len);
        bmp->bmiHeader.biClrUsed = 256;
        // etc...
        //...
        free(bmp);