简体   繁体   中英

How to initialize struct with an array?

Is there a better way of initializing a struct with an array than doing the following?

struct Parameters
{
    double distance;
    double radius;
    double strength;
    long distanceX;
    long distanceY;
    long clickX;
    long clickY;
};

void calculate(double dParameters[], long lParameters[])
{
    Parameters param = 
    {
        dParameters[0], 
        dParameters[1],
        dParameters[2],

        lParameters[0],
        lParameters[1],
        lParameters[2],
        lParameters[3]
    };
}

I thought of assigning pointers:

void calculate(double dParameters[], long lParameters[])
{
    Parameters param;
    (double*)(&param.distance) = &dParameters[0];
    (long*)(&param.distanceX) = &lParameters[0];
}

But I am not sure if it is valid in c++.

If you know the layout of the struct, and have carefully chosen to put all members of like type in order without anything between them, then you could use memcpy() .

memcpy(&param.distance, dParameters, sizeof(*dParameters) * 3);
memcpy(&param.distanceX, lParameters, sizeof(*lParameters) * 4);

This is rather fragile code, as distance must be the first double parameter of exactly four double parameters in a row, or you'll get corrupted data, and nothing will verify this at compile time.

It could be improved with offsetof to get and/or verify the length. Such as:

void calculate(double dParameters[], size_t n_dParameters, long lParameters[], size_t n_lParameters)
{
    Parameters param;

    assert(offsetof(Parameters, strength) - offsetof(Parameters, distance) == sizeof(*dParameters) * n_dParameters);
    memcpy(&param.distance, dParameters, offsetof(Parameters, strength) - offsetof(Parameters, distance));
    assert(offsetof(Parameters, clickY) - offsetof(Parameters, distanceX) == sizeof(*lParameters) * n_lParameters);
    memcpy(&param.distanceX, dParameters, offsetof(Parameters, clickY) - offsetof(Parameters, distanceX));
}

Historically, gcc has not been great at optimizing struct initialization, such as using the equivalent of memcpy() or memset() when it would be possible and beneficial. If your struct had a hundred fields, this might actually be useful.

Another technique would be use to a union to define both an array version and an individual field version of your struct.

struct ParametersArrays {
   double doubles[3];
   long longs[4];
};
union ParametersUnion {
   struct Parameters params;
   struct ParametersArrays arrays;
};
ParametersUnion u;
memcpy(u.arrays.doubles, dParameters, sizeof(u.arrays.doubles));
memcpy(u.arrays.longs, lParameters, sizeof(u.arrays.longs));
Parameters& p = u.params; // Now you can use p

Note that using more than one member of a union like this is not strictly legal in C++, but it is in C, and most/all C++ compilers will compile it as expected.

你的第二个例子是非法的,但优化器(知道实际布局)确实像那样实现了它。

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