Thomas T.
Thomas T.

Reputation: 65

Initializing a const array in a struct in C++


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.

Upvotes: 3

Views: 18206

Answers (2)

bikeshedder
bikeshedder

Reputation: 7487

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;
    }
};

Upvotes: 3

loganfsmyth
loganfsmyth

Reputation: 161657

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.

Upvotes: 4

Related Questions