Initializing complex, const, variably-sized structures at compiletime

Discussion in 'C++' started by spacewrench@gmail.com, Dec 23, 2008.

  1. Guest

    I'm working on a USB device framework for a microcontroller. USB
    requires manipulating many descriptor structures that are variably-
    sized. For example:

    struct StringDescriptor {
    unsigned len;
    wchar_t data[0];
    }

    (That's simpler than a real USB StringDescriptor, but it shows the
    essential feature, a variably-sized array of wchar_t's that contain
    the string data.)

    I would like to be able to declare these at compile time, and place
    them in Flash if appropriate:

    StringDescriptor might_be_modified( "Some String Value" );
    const StringDescriptor cannot_be_modified( "Fixed String Value" );

    Is there a clean way to declare StringDescriptor so that the
    declarations are simple and don't involve malloc(), new() or a run-
    time constructor invocation? All the code examples I've seen just
    declare an array of bytes, which has no type safety and poor
    readability.

    Thanks,
    , Dec 23, 2008
    #1
    1. Advertising

  2. Ian Collins Guest

    wrote:
    > I'm working on a USB device framework for a microcontroller. USB
    > requires manipulating many descriptor structures that are variably-
    > sized. For example:
    >
    > struct StringDescriptor {
    > unsigned len;
    > wchar_t data[0];
    > }
    >
    > (That's simpler than a real USB StringDescriptor, but it shows the
    > essential feature, a variably-sized array of wchar_t's that contain
    > the string data.)
    >
    > I would like to be able to declare these at compile time, and place
    > them in Flash if appropriate:
    >
    > StringDescriptor might_be_modified( "Some String Value" );
    > const StringDescriptor cannot_be_modified( "Fixed String Value" );
    >

    Something like (simplified with char):

    template <size_t N>
    struct StringDescriptor {
    unsigned len;
    char data[N];
    };

    const char* fixed = "Fixed String Value";

    const StringDescriptor<sizeof("Fixed String Value")> cannot_be_modified
    = {sizeof("Fixed String Value"), "Fixed String Value" };

    --
    Ian Collins
    Ian Collins, Dec 23, 2008
    #2
    1. Advertising

  3. spacewrench Guest

    Thanks for the replies. I thought there might be an arcane
    template<T> way of doing this, but perhaps not. I don't mind a GCC-
    only solution, so I'm currently investigating a cpp macro that turns
    into asm("..."). I've got the first part of it working OK (gas-2.19
    has a ".string16" pseudo-op that comes in handy!). Next is figuring
    out how to turn these asm blobs into small-integer indices into an
    array of pointers to StringDescriptors.

    The ultimate goal is to be able to say:

    DeviceDescriptor x = {
    .ManufacturerString = CONST_STRING_DESCRIPTOR( "Acme Industries" ),
    .ProductString = STRING_DESCRIPTOR( "Frobozz 3200" )
    } ;

    [Struct initialization syntax might be wrong, but you get the idea.]

    ....with ManufacturerString set to n and ProductString set to (n+1),
    and GlobalStringDescriptors[n] = StringDescriptor( "Acme
    Industries" ), GlobalStringDescriptors[n+1] = StringDescriptor
    ( "Frobozz 3200" ). (The "Acme Industries" string should live in
    Flash / .rodata.)

    I'll post the solution if I find one.

    Regards,
    d.
    spacewrench, Dec 23, 2008
    #3
  4. Ian Collins a écrit :
    > wrote:
    >[snip]
    > Something like (simplified with char):
    >
    > template <size_t N>
    > struct StringDescriptor {
    > unsigned len;
    > char data[N];
    > };
    >
    > const char* fixed = "Fixed String Value";


    You must mean:
    const char fixed[] = "Fixed String Value";

    > const StringDescriptor<sizeof("Fixed String Value")> cannot_be_modified
    > = {sizeof("Fixed String Value"), "Fixed String Value" };
    Michael DOUBEZ, Dec 23, 2008
    #4
  5. James Kanze Guest

    On Dec 23, 3:17 am, wrote:
    > I'm working on a USB device framework for a microcontroller.
    > USB requires manipulating many descriptor structures that are
    > variably- sized. For example:


    > struct StringDescriptor {
    > unsigned len;
    > wchar_t data[0];
    > }


    That's not a legal definition, neither in C nor in C++.

    > (That's simpler than a real USB StringDescriptor, but it shows
    > the essential feature, a variably-sized array of wchar_t's
    > that contain the string data.)


    In fact, what you want is a flexible array member: an incomplete
    array type as the last element (in which case, the final
    declaration should be "wchar_t data[];"). That's only supported
    in C99, not C++ nor C90.

    Some compilers may allow it as an extension. (I believe that
    some compilers also allow the 0 sized array in this case, again
    as an extension.)

    > I would like to be able to declare these at compile time, and
    > place them in Flash if appropriate:


    > StringDescriptor might_be_modified( "Some String Value" );
    > const StringDescriptor cannot_be_modified( "Fixed String Value" );


    > Is there a clean way to declare StringDescriptor so that the
    > declarations are simple and don't involve malloc(), new() or a
    > run- time constructor invocation?


    struct StringDescriptor
    {
    unsigned length ;
    wchar_t* data ;
    } ;

    wchar_t const string_cannot_be_modifed[]
    = L"Fixed String Value" ;
    StringDescriptor const
    cannot_be_modified =
    {
    sizeof( string_cannot_be_modifed ) - 1,
    string_cannot_be_modifed
    } ;

    > All the code examples I've seen just declare an array of
    > bytes, which has no type safety and poor readability.


    One can argue about readability; for something like the above,
    I'll usually use a simple script to generate it, rather than
    write it all out by hand.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Dec 23, 2008
    #5
  6. James Kanze Guest

    On Dec 23, 9:56 am, Michael DOUBEZ <> wrote:
    > Ian Collins a écrit :


    > > wrote:
    > >[snip]
    > > Something like (simplified with char):


    > > template <size_t N>
    > > struct StringDescriptor {
    > > unsigned len;
    > > char data[N];
    > > };


    > > const char* fixed = "Fixed String Value";


    > You must mean:
    > const char fixed[] = "Fixed String Value";


    It doesn't matter, since he never uses it.

    > > const StringDescriptor<sizeof("Fixed String Value")> cannot_be_modified
    > > = {sizeof("Fixed String Value"), "Fixed String Value" };


    The problem with this solution is that you don't have a simple
    StringDescriptor type, which is probably what his functions
    expect.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Dec 23, 2008
    #6
  7. James Kanze a écrit :
    > On Dec 23, 9:56 am, Michael DOUBEZ <> wrote:
    >> Ian Collins a écrit :

    >
    >>> wrote:
    >>> [snip]
    >>> Something like (simplified with char):

    >
    >>> template <size_t N>
    >>> struct StringDescriptor {
    >>> unsigned len;
    >>> char data[N];
    >>> };

    >
    >>> const char* fixed = "Fixed String Value";

    >
    >> You must mean:
    >> const char fixed[] = "Fixed String Value";

    >
    > It doesn't matter, since he never uses it.


    Funny how mind works.

    >
    >>> const StringDescriptor<sizeof("Fixed String Value")> cannot_be_modified
    >>> = {sizeof("Fixed String Value"), "Fixed String Value" };

    >
    > The problem with this solution is that you don't have a simple
    > StringDescriptor type, which is probably what his functions
    > expect.


    Not necessarily, he can get away with default parameters and mutation.

    template <size_t N = 0 /* or any minimal size */>
    struct StringDescriptorImp {
    unsigned len;
    char data[N];

    //define only const version since N>0 should reside in RO data
    operator const StringDescriptorImp<>&()const{
    assert( N >= 0 /* minimal size */ );
    return *reinterpret_cast<constStringDescriptorImp<>*>(this);
    }
    };

    typedef StringDescriptorImp<> StringDescriptor;

    So he gets a default StringDescriptor type and can use
    StringDescriptorImp to place data somewhere in flash.

    I admit the cast is a bit ugly and formally invoke undefined behavior
    but in embedded systems, this is usually under control.

    --
    Michael
    Michael DOUBEZ, Dec 23, 2008
    #7
  8. James Kanze a écrit :
    > On Dec 23, 3:17 am, wrote:
    >> I'm working on a USB device framework for a microcontroller.
    >> USB requires manipulating many descriptor structures that are
    >> variably- sized. For example:

    >
    >> struct StringDescriptor {
    >> unsigned len;
    >> wchar_t data[0];
    >> }

    >
    > That's not a legal definition, neither in C nor in C++.
    >
    >> (That's simpler than a real USB StringDescriptor, but it shows
    >> the essential feature, a variably-sized array of wchar_t's
    >> that contain the string data.)

    >
    > In fact, what you want is a flexible array member: an incomplete
    > array type as the last element (in which case, the final
    > declaration should be "wchar_t data[];"). That's only supported
    > in C99, not C++ nor C90.
    >
    > Some compilers may allow it as an extension. (I believe that
    > some compilers also allow the 0 sized array in this case, again
    > as an extension.)


    I know IAR and ARM tools do support it. I believe it is quite common.
    Perhaps it is part of the embedded-C++ specs, I have never checked.

    >> I would like to be able to declare these at compile time, and
    >> place them in Flash if appropriate:

    >
    >> StringDescriptor might_be_modified( "Some String Value" );
    >> const StringDescriptor cannot_be_modified( "Fixed String Value" );

    >
    >> Is there a clean way to declare StringDescriptor so that the
    >> declarations are simple and don't involve malloc(), new() or a
    >> run- time constructor invocation?

    >
    > struct StringDescriptor
    > {
    > unsigned length ;
    > wchar_t* data ;
    > } ;
    >
    > wchar_t const string_cannot_be_modifed[]
    > = L"Fixed String Value" ;
    > StringDescriptor const
    > cannot_be_modified =
    > {
    > sizeof( string_cannot_be_modifed ) - 1,
    > string_cannot_be_modifed
    > } ;


    As I understand the OP problem, he wants to put them in RO area and use
    them directly to answer some request. What he is actually describing is
    the answer message (or part of it) and the layout wanted is the
    serialized version of the data.

    >> All the code examples I've seen just declare an array of
    >> bytes, which has no type safety and poor readability.

    > One can argue about readability; for something like the above,
    > I'll usually use a simple script to generate it, rather than
    > write it all out by hand.


    IMHO, this is the few case when a macro is justified. This is what we
    use when describing the layout of the configuration space in flash on
    our system.

    --
    Michael
    Michael DOUBEZ, Dec 23, 2008
    #8
  9. James Kanze Guest

    On Dec 23, 12:26 pm, Michael DOUBEZ <> wrote:
    > James Kanze a écrit :
    > > On Dec 23, 3:17 am, wrote:
    > >> I'm working on a USB device framework for a microcontroller.
    > >> USB requires manipulating many descriptor structures that are
    > >> variably- sized. For example:


    > >> struct StringDescriptor {
    > >> unsigned len;
    > >> wchar_t data[0];
    > >> }


    > > That's not a legal definition, neither in C nor in C++.


    > >> (That's simpler than a real USB StringDescriptor, but it shows
    > >> the essential feature, a variably-sized array of wchar_t's
    > >> that contain the string data.)


    > > In fact, what you want is a flexible array member: an
    > > incomplete array type as the last element (in which case,
    > > the final declaration should be "wchar_t data[];"). That's
    > > only supported in C99, not C++ nor C90.


    > > Some compilers may allow it as an extension. (I believe
    > > that some compilers also allow the 0 sized array in this
    > > case, again as an extension.)


    > I know IAR and ARM tools do support it. I believe it is quite
    > common. Perhaps it is part of the embedded-C++ specs, I have
    > never checked.


    The only compiler I have that accepts it with my usual options
    is VC++. G++ will accept it as well, IF you forget to specify
    -std=c++98. Never the less, the C standard explicitly forbids
    it (and C++ just copies C here).

    > >> I would like to be able to declare these at compile time,
    > >> and place them in Flash if appropriate:


    > >> StringDescriptor might_be_modified( "Some String Value" );
    > >> const StringDescriptor cannot_be_modified( "Fixed String Value" );


    > >> Is there a clean way to declare StringDescriptor so that
    > >> the declarations are simple and don't involve malloc(),
    > >> new() or a run- time constructor invocation?


    > > struct StringDescriptor
    > > {
    > > unsigned length ;
    > > wchar_t* data ;
    > > } ;


    > > wchar_t const string_cannot_be_modifed[]
    > > = L"Fixed String Value" ;
    > > StringDescriptor const
    > > cannot_be_modified =
    > > {
    > > sizeof( string_cannot_be_modifed ) - 1,
    > > string_cannot_be_modifed
    > > } ;


    > As I understand the OP problem, he wants to put them in RO
    > area and use them directly to answer some request. What he is
    > actually describing is the answer message (or part of it) and
    > the layout wanted is the serialized version of the data.


    You mean that he wants to be able to do a simple write of the
    bytes, with no formatting? That wouldn't be very clean to begin
    with. (On the other hand, in some embedded environments, it
    might be justified.) The only real way to do that is with a
    char const[]; it wouldn't be too difficult to generate them
    automatically.

    > >> All the code examples I've seen just declare an array of
    > >> bytes, which has no type safety and poor readability.

    > > One can argue about readability; for something like the
    > > above, I'll usually use a simple script to generate it,
    > > rather than write it all out by hand.


    > IMHO, this is the few case when a macro is justified. This is
    > what we use when describing the layout of the configuration
    > space in flash on our system.


    Nothing against a macro in this case either, but I think that
    automatic generation will work better, since it can count the
    characters for you (although come to think of it, you could
    probably do this with a macro as well, as long as the macro was
    only used with string literals).

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Dec 23, 2008
    #9
  10. spacewrench Guest

    On Dec 23, 3:26 am, Michael DOUBEZ <> wrote:

    > What he is actually describing is
    > the answer message (or part of it) and the layout wanted is the
    > serialized version of the data.


    Yes, that's it. I should have thought to describe it that way. I
    need the descriptors in serialized form for some purposes, and the
    information is accessible easily enough in that form, so I can save
    code & data space by simply storing & using them in serialized form
    always. My question should have been, how to get the compiler to put
    them in that form, without the editing/maintenance hassle of what
    everybody else seems to do:

    const char FooStrDscr[] = { 6, 'F', 0, 'o', 0, 'o', 0 } ;
    const char WazooStrDscr[] = { 10, 'W', 0, 'a', 0, 'z', 0, 'o', 0, 'o',
    0 };

    const char * const StrDscrTbl[] = { FooStrDscr, WazooStrDscr };

    #define FooStrDscrIdx 0
    #define WazooStrDscrIdx 1

    I could probably hack something together using lots of GNU features,
    but when I started looking at the linker scripts (necessary, I think,
    to put all the StrDscr pointers in a single table so I can
    automagically generate integer indices to reference them), it's
    hairier than the standard approach. Given how little time the program
    spends fiddling with these descriptors anyway, and the fact that they
    don't get changed _that_ often, it makes sense to waste my time
    elsewhere.

    Thanks, everyone.
    spacewrench, Dec 23, 2008
    #10
  11. On Dec 23, 2:17 am, wrote:
    > I'm working on a USB device framework for a microcontroller. USB
    > requires manipulating many descriptor structures that are variably-
    > sized. For example:
    >
    > struct StringDescriptor {
    > unsigned len;
    > wchar_t data[0];
    > }
    >
    > [...]
    >
    > I would like to be able to declare these at compile time, and place
    > them in Flash if appropriate:
    >
    > StringDescriptor might_be_modified( "Some String Value" );
    > const StringDescriptor cannot_be_modified( "Fixed String Value" );
    >
    > Is there a clean way to declare StringDescriptor so that the
    > declarations are simple and don't involve malloc(), new() or a run-
    > time constructor invocation? All the code examples I've seen just
    > declare an array of bytes, which has no type safety and poor
    > readability.


    Yes. To give the descriptor proper type in C++ you have to pry apart
    the static and dynamic parts, i.e. the static descriptor head and the
    dynamic data part. Then use an accessor function to access the data
    part:

    struct StringDescriptor {
    unsigned len;
    };

    inline
    const wchar_t* data (const StringDescriptor& s) {
    assert (s.len > 0);
    return reinterpret_cast <const wchar_t*>
    (reinterpret_cast <const char*> (&s) + sizeof (s));
    }

    Here I've used a free function, but if you prefer you can of course
    make it a member. Usage:

    void process_str (const StringDescriptor& s) {
    wcout << data (s) << endl;
    }

    To address the second part of your post, initialization, you can use a
    template with a conversion function:

    template <size_t N>
    struct StringDescriptorN {
    unsigned len;
    wchar_t data [N];
    operator const StringDescriptor& () const {
    return reinterpret_cast <const StringDescriptor&>
    (*this);
    }
    };

    Usage:

    const StringDescriptorN <6> foo = {6, L"Foo"};
    process_str (foo);

    To further simplify declarations, you can use a macro:

    #define DECL_STR_DSCR(name, str) \
    StringDescriptorN <sizeof (str)> name = \
    {sizeof (str), str};

    Usage:

    const DECL_STR_DSCR (wazoo, L"Wazoo");
    process_str (wazoo);

    You can make similar templates and macros to handle your descriptor
    tables.

    Regards,
    Vidar Hasfjord
    Vidar Hasfjord, Dec 24, 2008
    #11
  12. spacewrench Guest

    On Dec 24, 4:50 am, Vidar Hasfjord <>
    wrote:

    > To address the second part of your post, initialization, you can use a
    > template with a conversion function:
    >
    >   template <size_t N>
    >   struct StringDescriptorN {
    >     unsigned len;
    >     wchar_t data [N];
    >     operator const StringDescriptor& () const {
    >       return reinterpret_cast <const StringDescriptor&>
    >         (*this);
    >     }
    >   };


    Ooh, that's a great idea! Except I could even do:

    struct StringDescriptor {
    unsigned len;
    const wchar_t *get_data( void ) const { return (wchar_t *)(&len +
    1); }
    } ;

    template <size_t N>
    struct StringDescriptorBody : public StringDescriptor {
    wchar_t data[N];
    } ;

    Then I don't even need the conversion operator in the template. (Or
    perhaps I still do, for some reason that my c++-fu is not yet adequate
    to understand. I'll have to play with this a bit. There's still the
    problem of getting the wchar_t's into little-endian order on machines
    where that's not the default...yuck.)

    Thanks!
    spacewrench, Dec 24, 2008
    #12
  13. On Dec 24, 5:34 pm, spacewrench <> wrote:
    > On Dec 24, 4:50 am, Vidar Hasfjord <>
    > wrote:
    > [...]
    >
    > Ooh, that's a great idea!  Except I could even do:
    >
    > struct StringDescriptor {
    >   unsigned len;
    >   const wchar_t *get_data( void ) const { return (wchar_t *)(&len +
    > 1); }
    >
    > } ;


    Yes, my cast to char pointer was unnecessary. I prefer
    reinterpret_cast though.

    > template <size_t N>
    > struct StringDescriptorBody : public StringDescriptor {
    >   wchar_t data[N];
    >
    > } ;
    >
    > Then I don't even need the conversion operator in the template.  (Or
    > perhaps I still do, for some reason that my c++-fu is not yet adequate
    > to understand.


    Unfortunately, that will not work. You cannot use inheritance, because
    initializer lists can only be used with POD types. Hence the
    conversion operator is needed.

    > I'll have to play with this a bit.  There's still the
    > problem of getting the wchar_t's into little-endian order on machines
    > where that's not the default...yuck.)


    That sounds like a IO problem that hopefully is orthogonal to the
    initialization issue.

    See below for corrected and simplified code that should work with
    Windows Driver Kit's USB library. Here the template converts to the
    Windows' struct which has a placeholder string member of size 1.

    namespace usb {


    const UCHAR string_descriptor_typetag =
    USB_STRING_DESCRIPTOR_TYPE;


    template <size_t N>
    struct StringDescriptor {
    UCHAR bLength; // size in bytes of descriptor
    UCHAR bDescriptorType;
    wchar_t bString [N];

    operator const USB_STRING_DESCRIPTOR& () const {
    assert (bLength == sizeof (*this));
    assert (bDescriptorType == string_descriptor_typetag);
    return reinterpret_cast <const USB_STRING_DESCRIPTOR&>
    (*this);
    }
    };


    template <>
    struct StringDescriptor <0>; // undefined


    } // namespace


    // Test utilities


    void log (const USB_STRING_DESCRIPTOR& s) {
    wcout << "USB_STRING_DESCRIPTOR {"
    << "length = " << s.bLength
    << ", type = " << s.bDescriptorType
    << ", string = " << s.bString
    << "}" << endl;
    }


    #define ARRAY_SIZE(a) \
    (sizeof (a) / sizeof (a [0]))

    #define DECL_USB_STR_DSCR(name, str) \
    usb::StringDescriptor <ARRAY_SIZE (str)> name = \
    {sizeof (name), usb::string_descriptor_typetag, str};


    void test_variable_array ()
    {
    const DECL_USB_STR_DSCR (foo, L"Foo");
    log (foo);

    const DECL_USB_STR_DSCR (wazoo, L"Wazoo");
    log (wazoo);
    }

    Regards,
    Vidar Hasfjord
    Vidar Hasfjord, Dec 24, 2008
    #13
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. thechaosengine

    Oddly sized sized password textbox

    thechaosengine, Sep 15, 2005, in forum: ASP .Net
    Replies:
    1
    Views:
    581
    David Hearn
    Sep 15, 2005
  2. jjleto
    Replies:
    2
    Views:
    381
    jjleto
    Nov 12, 2004
  3. Alfonso Morra
    Replies:
    11
    Views:
    711
    Emmanuel Delahaye
    Sep 24, 2005
  4. Javier
    Replies:
    2
    Views:
    558
    James Kanze
    Sep 4, 2007
  5. Poster Matt
    Replies:
    21
    Views:
    1,696
    Poster Matt
    Jun 16, 2010
Loading...

Share This Page