Initializing a const array in a struct in C++

14,493

Solution 1

I would recommend against any kind of casting of structs to raw memory unless you are using some kernel interface which is guaranteed to run on the same machine and is supposed to be used that way.

This is not portable (endian issues), every compiler does it a little different and the performance really is not so much better. All in all it does not justify this bad practice.

The reason why your code example doesn't work are the static members. Since static members are not part of the object (but the class) only UMID and crc are written that way.

struct PAYLOAD_INFO {
    const uint8_t magicnumber[4] = { 0xFA, 0x11, 0x28, 0x33 };
    uint16_t UMID;
    const uint16_t VID = 1487 ;
    uint32_t crc;
};

This code only works in C++11, but since you include cstdint I'm assume that you already use that C++ version. If you don't use C++11 you need to initialize the members in the constructor and you must not use const for the magic number because it can not be initialized. (See: initialize a const array in a class initializer in C++)

struct PAYLOAD_INFO {
    const uint8_t magicnumber[4] = { 0xFA, 0x11, 0x28, 0x33 };
    uint16_t UMID;
    const uint16_t VID = 1487 ;
    uint32_t crc;
};

For C++98 you need to do:

struct PAYLOAD_INFO {
    uint8_t magicnumber[4];
    uint16_t UMID;
    const uint16_t VID;
    uint32_t crc;
    PAYLOAD_INFO() : VID(1487)
    {
        magicnumber[0] = 0xFA;
        magicnumber[1] = 0x11;
        magicnumber[2] = 0x28;
        magicnumber[3] = 0x33;
    }
};

Solution 2

Your static is currently just defining a global static. You need to add a class specifier to define the static to be part of your class.

const uint8_t PAYLOAD_INFO::magicnumber[4] = { 0xFA, 0x11 , 0x28 , 0x33 };

That said, as @bikeshedder mentions below, statics are stored separately in memory, so when you create a new instance of your struct, that instance will not include the magic numbers in the instance's memory location, so your usage of writeToFile will not work as you expect.

Share:
14,493

Related videos on Youtube

Thomas T.
Author by

Thomas T.

Updated on September 30, 2022

Comments

  • Thomas T.
    Thomas T. over 1 year


    I have to work on an prop. binary file format and want to realize it with the use of structs.
    I need constant byte sequence in my structs and atm I don't get it how to realize that.

    I thought about something like that:

    #include <cstdint>
    #pragma pack(push,1)
    
    typedef struct PAYLOAD_INFO {
        const uint8_t magicnumber[4] =  { 0xFA, 0x11 , 0x28 , 0x33 };
        uint16_t UMID;
        const uint16_t VID = 1487 ;
        uint32_t crc;
    };
    
    #pragma pack(pop)
    
    int main (){
      PAYLOAD_INFO pldInst;
      pldInst.UMID = 5;
      pldInst.crc = 0x34235a54;
      ...
      writeToFile(&PAYLOAD_INFO,sizeof(PAYLOAD_INFO));
    }
    

    In the end "pldInst" should look some like that ( in the memory) , without regard of the byteorder in this example:

    0x00000000:  0xFA, 0x11 , 0x28 , 0x33
    0x00000004:  0x00, 0x05 , 0x05 , 0xCF
    0x00000008:  0x34, 0x23 , 0x5a , 0x54
    

    I already tried the "default" approach:

    #include <cstdint>
    #pragma pack(push,1)
    
    typedef struct PAYLOAD_INFO {
        static const uint8_t magicnumber[4];
        uint16_t UMID;
        static const uint16_t VID = 1487 ;
        uint32_t crc;
    };
    
    const uint8_t magicnumber[4] =  { 0xFA, 0x11 , 0x28 , 0x33 };
    
    #pragma pack(pop)
    

    but doesn't work as intend.

    Is there a way to get this done without calculating the memory size of every struct member,allocating new memory and copying every member ?

    I using g++ 4.6.3.

    Regard, Thomas

    UPDATE:
    The the c++11 solution provided by @bikeshedder works very well but it compiles only with g++ 4.7 or higher.

    • loganfsmyth
      loganfsmyth over 11 years
      I think you need const uint8_t PAYLOAD_INFO::magicnumber[4] = .... Not 100% though.
  • Thomas T.
    Thomas T. over 11 years
    I using c++11 and got now an "sorry, unimplemented: non-static data member initializers". A switch to g++ 4.7.2 fixed it. The byte order isn't critical in my case because I finally realize from the provided binary library with "writeToFile" uses POSIX htonX before writing. Thank you for you help.