Need construct for member relative location placement in huge structures

Here is the problem :  I have this huge structure whose members have address restrictions (e.g. member x starts from relative address y from the base pointer B).  The address restricted members(from base) are needed to satisfy the hardware device register specification of the device.  For example,

typedef struct _DeviceRegMap {
    struct PCIDeviceHeader PDH;  // Bytes 0 - 199
    //put fillers here as the next structure should always
    //start 300 bytes (absolute) from the base of this structure
    BYTE filler[100];
    struct PCIDeviceSpecificStruct PDSS; //Bytes 300 - 425
    ...
    ...
    ...
}DeviceRegMap, *PDeviceRegMap;

In the above structure definition, because of the lack of any construct to instrcut the compiler to place the PDSS member always at 300 byte location relative from the base, I had to put filler member.

The issue is that the structure DeviceRegMap contains multiple structure types like the PDSS over a vast memory space of 512KB.   Putting the fillers aren't a good idea since, if someone changes the structure definition that precedes the PDSS resulting in a size change, then we have to make sure the filler gets its array size changed manually.  Doing this over a huge structure definition is a code maintenance nightmare.

Neither the __declspec(align(#)) directive going to be useful since this is not an alignment restriction but relative location restriction.

Is there a way to solve this issue  

(IdeaBTW, I guess implicitly I have here hinted a solution to for compiler developers assuming that this problem can't be solved with current compiler products.  I am interested in exploring further solutions in this space if needed).


Thanks
Srini


Answer this question

Need construct for member relative location placement in huge structures

  • sanjeewa

    As I noted, you can write a miniprogram to save yourself all that typing (and the concomitant typo risk):

    # some data file in your build process
    struct PCIDeviceHeader PDHBase;
    struct PCIDeviceH1 PDH1;
    BYTE Reserved[35];
    struct b;
    struct c;
    struct d;
    unsigned int PCIFlagB;
    [set_offset(300)]
    struct PCIDeviceSpecificStruct PDSS;
    (etc)

    your miniprogram reads this file and autogenerates the struct definition.

    Here's another solution though it uses a nonstandard language extension.

    struct DeviceRegMap {
    __declspec(property(getPDHBase)) PCIDeviceHeader& PDHBase;
    PCIDeviceHeader& getPDHBase() { return *(PCHDeviceHeader*)this; }
    ...
    __declspec(property(getPDSS)) PCIDeviceSpecificStruct& PDSS;
    PCIDeviceSpecificStruct& getPDSS() { return *(PCIDeviceSpecificStruct*)((BYTE*)this+300); }
    ...
    };

  • cmb082000

    typedef struct _DeviceRegMap {
     struct PCIDeviceHeader PDH;
     BYTE filler[300 - sizeof(struct PCIDeviceHeader)];
     struct PCIDeviceSpecificStruct PDSS;
     BYTE filler[100 - sizeof(struct PCIDeviceSpecificStruct)];
     ...
    };

    to save typing you could write a miniprogram to generate the structure declaration.

  • SHASHIVRAT

    Jochen,

    Please re-visit my first post in this thread...   The location of the members are very important as the device reads from this location.  So, filler is absolutely necessary.   BTW, I am not writing into file... I am not sure what you refer by writing in file.   This is a structure that lives in the kernel address space inside a driver that shares this piece of memory with the hardware device.

  • Yoav Sion

    Folks,

    Thanks for your interest first.

    Though the answers are little bit convincing, the solution is not good enough to tackle the code nightmare.  For the sake of simplicity to discuss I have overly simplified my code sample.  

    The issue is that in a complex production code base, there would be multiple data types before the filler that the code becomes very hard to look at and maintain...

    Here is the example where the solution of self-adjustible size byte fillers isn't practical enough to address :

    typedef struct _DeviceRegMap {
        struct PCIDeviceHeader PDHBase;  // Bytes 0 - 15
        struct PCIDeviceH1       PDH1;      // Bytes 16 -25
        BYTE  Reserved[35];                   //          26 - 60
        struct b;
        struct c;
        struct d;
         ...
         ... 
        unsigned int PCIFlagB;     

        //put fillers here as the next structure should always
        //start 300 bytes (absolute) from the base of this structure

       
    BYTE filler[300 - (sizeof (PDHBase)  +  
                                sizeof (PDH1)      +
                                sizeof (Reserved) +
                                sizeof (struct b)   +
                                sizeof (struct c)   +
                                sizeof (struct d)  ];
        struct PCIDeviceSpecificStruct PDSS; //Bytes 300 - 425
        ...
        ...
        ...
    }DeviceRegMap, *PDeviceRegMap;


    There are 2 issues with this solution :

    a)  In a massive structure definition where there ~80 structure definitions before a filler is a nightmare since the array size computation adjustment code looks awful.

    b) This method is a maintenance nightmare -  Imagine a naive recent college grad. fixes a bug and removes one of the struct and probably doesn't delete the correspoding sizeof() entry out of the array size computation...  Ouch my entire production is in trouble.

    Can we think of better ones

    Thanks
    Malayala Srinivasan


  • SlinkingFerret

    One idea - break each contiguous sub-range out into it's own sub-type.

    typedef struct _DeviceSegment1 {
        struct PCIDeviceHeader PDHBase;  // Bytes 0 - 15
        struct PCIDeviceH1       PDH1;      // Bytes 16 -25
        BYTE  Reserved[35];                   //          26 - 60
        struct b;
        struct c;
        struct d;
         ...
         ... 
        unsigned int PCIFlagB;     
    } S1;

    typedef struct _DeviceSegment2 {
        struct PCIDeviceSpecificStruct PDSS; //Bytes 300 - 425
        ...
        ...
        ...
    } S2;

    typedef struct _DeviceRegMap {
        S1 s1;
        //put fillers here as the next structure should always
        //start 300 bytes (absolute) from the base of this structure

       
    BYTE filler[300 - (sizeof (S1)  ];
        S2 s2;
    }DeviceRegMap, *PDeviceRegMap;


    All in all, I'd probably take one of two approaches:

    1. Don't try to define a single struct that covers the entire device space.
    or
    2. As Raymond Chen suggested, write a tool that will generate the struct definition given some other text definition of the device space.  There are lots of C-parser bits out on the net that could be useful in constructing such a tool.

    -cd

  • TomSt

    Hi msreeni!

    An other question: Why do you need the "filler"

    If it is just for storing the structure into a file I would recomend, that you write it not as one write-operation, instead write the parts separately and do the filling in your write-operation.

    Greetings
      Jochen


  • DigDig

    Raymond Chen@discussions.microsoft.com wrote:
    typedef struct _DeviceRegMap {
     struct PCIDeviceHeader PDH;
     BYTE filler[300 - sizeof(struct PCIDeviceHeader)];
     struct PCIDeviceSpecificStruct PDSS;
     BYTE filler[100 - sizeof(struct PCIDeviceSpecificStruct)];
     ...
    };

    to save typing you could write a miniprogram to generate the structure declaration.
    But you should not forget to set the Alignment to 1.

  • Need construct for member relative location placement in huge structures