0

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++.

1
  • You have a struct. It contains all values you need. So create an array-of-struct to hold all of the instances of the struct you need and pass the array of struct (e.g. a pointer to the 1st struct in the array) as your parameter and then process the array with all values within your function. Commented Dec 6, 2019 at 8:15

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

Comments

0

Your second example is illegal, but chances are that the optimizer (knowing the actual layout) does implement it like that.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.