简体   繁体   中英

Initializing C struct with unions declared in C++17

This question is specifically about options in C++17 . Assuming following declaration in C library (I cannot change them):

typedef enum {
    TYPEA = 0,
    TYPEB = 2,
    TYPEC = 4
} SPECIFIC_TYPE_t;

typedef struct {
    uint16_t Method : 1;
    uint16_t Access : 2;
    uint16_t VendorSpecific : 1;
    uint16_t Direction : 1;
    uint16_t Persistent : 1;
    uint16_t Internal : 4;
    uint16_t Reserved : 6;           
} PROPERTY_t;

typedef RESULT_t (*CB_DataPointRead_t) (void *Service, uint8_t Pinpoint, bool VendorSpecific,
                                        uint16_t GroupID, uint16_t ElementID, void *Data,
                                        uint8_t *DataLengthInOut);
typedef RESULT_t (*CB_DataPointWrite_t) (void *service, uint8_t Pinpoint, bool VendorSpecific,
                                         uint16_t GroupID, uint16_t ElementID, void *Data,
                                         uint8_t DataLength);

typedef struct {
    uint16_t GroupID;
    uint16_t ElementID;
    uint8_t Pinpoint;
    SPECIFIC_TYPE_t Type;
    uint8_t Size;
    PROPERTY_t Property;
    union {
        struct {
            CB_DataPointRead_t Read;
            CB_DataPointWrite_t Write;
        } Callback;
        struct {
            void *Data;
        } DirectAccess;
    } AccessType;
} DataPoint_t;

Status in pure C

To initialize the last element designator initializers work well in C:

uint16t dataPointValue = 0;
const DataPoint_t firstDatapointConfig = {
    /*...*/,
    .DirectAccess = { (void*)&dataPointValue; }
};

Designator initializers in C++

They appear in C++20 and aren't compatible with C in many aspects.

Problem

I'd like to initialize variable like firstDatapointConfig as const qualified in C++17. So far I don't see a way other than write a function in C (compiled as C code) and return the initialized structure to a variable before use. I tried various ways, including gnuc++17 which handles designator initializers, except it tells me:

error: 'const DataPoint_t' has no non-static data member named 'DirectAccess'

and MSVC don't digest this method of initialization at all without C++20 enabled.

Addressing the last element outside initializer, don't work either:

datapoint.DirectAccess = { &value };

results in the following error:

error: 'struct DataPoint_t' has no member named 'DirectAccess'

Comment

It was much easier to use these structures in Rust after processing them through bindgen:-)

Question

Is there a way to initialize the variable of DataPoint_t type in C++17 with DirectAccess element filled with the right value?

Is there a way to initialize the variable of DataPoint_t type in C++17 with DirectAccess element filled with the right value?

Yes, even though my way of doing it is a little cumbersome. There may be easier ways:

// Make a usable type of that anonymous entity:
using AccessType_t = decltype(DataPoint_t::AccessType);

// Use the new type and prepare what you need:
AccessType_t at;
at.DirectAccess.Data = nullptr;

// initialize your DataPoint_t
const DataPoint_t firstDatapointConfig{1,2,3,TYPEA,4, PROPERTY_t{}, at};

If you do this a lot you could make a helper function:

using AccessType_t = decltype(DataPoint_t::AccessType);
using Callback_t = decltype(AccessType_t::Callback);    
using DirectAccess_t = decltype(AccessType_t::DirectAccess);

template<class U>
constexpr auto init_AccessType(U u) {
    AccessType_t at;

    if constexpr (std::is_same_v<U,Callback_t>) {
        at.Callback = u;
    } else if constexpr (std::is_same_v<U,DirectAccess_t>) {
        at.DirectAccess = u;
    } else {
        // uninitialized
    }
    return at;
}

const DataPoint_t firstDatapointConfig{1,2,3,TYPEA,4, PROPERTY_t{},
                                       init_AccessType(DirectAccess_t{nullptr})};

I'd like to initialize variable like firstDatapointConfig as const qualified in C++17

With all that C++ has to offer:

constexpr DataPoint_t create_DataPoint_t(uint16_t *v) {
    DataPoint_t r{};
    r.AccessType.DirectAccess.Data = v;
    return r;
}    
const DataPoint_t firstDatapointConfig = create_DataPoint_t(&dataPointValue);

with designated initializers:

const DataPoint_t firstDatapointConfig2 = {
    .AccessType = {
        .DirectAccess = {
            .Data = &dataPointValue
        }
    }
};

Addressing the last element outside initializer, don't work either:

 datapoint.DirectAccess = { &value };

Because there is no such element, there is datapoint.AccessType.DirectAccess.Data .

To initialize the last element designator initializers work well in C:

 uint16t dataPointValue = 0; const DataPoint_t firstDatapointConfig = { /*...*/, .DirectAccess = { (void*)&dataPointValue; } };

The presented code is invalid - uint16t is meant to be uint16_t and ; is a typo. And still after fixing the typos, no, the presented code is invalid in "pure C" and "does not work well" godbolt link . There is no such thing as DirectAccess in DataPoint_t - there is such member in the unnamed union declared inside DataPoint_t . You can do in C :

const DataPoint_t firstDatapointConfig3_in_C = {
    .AccessType = {
        .DirectAccess = { (void*)&dataPointValue }
    }
};

or

const DataPoint_t firstDatapointConfig4_in_C = {
    .AccessType.DirectAccess = { (void*)&dataPointValue }
};

or

const DataPoint_t firstDatapointConfig4_in_C = {
    .AccessType.DirectAccess.Data = (void*)&dataPointValue
};

The cast to void* is superfluous - all pointers are implicitly converted to void* . Note that the following:

const DataPoint_t firstDatapointConfig5_in_C = {
    .AccessType = { (void*)&dataPointValue }
};

would be equal to:

const DataPoint_t firstDatapointConfig6_in_C = {
    .AccessType.Callback.Read = (void*)&dataPointValue
};

Most probably you are coding under -fms-extensions with GNU gcc or with MSVC, in which case you should be aware that you are using an extension that imports unnamed structure members to parent structure . The code is invalid in "pure C", it's using an extension to C.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM