So I have the following available:
struct data_t {
char field1[10];
char field2[20];
char field3[30];
};
const char *getData(const char *key);
const char *field_keys[] = { "key1", "key2", "key3" };
This code is given to my and I cannot modify it in any way. It comes from some old C project.
I need to fill in the struct using the getData
function with the different keys, something like the following:
struct data_t my_data;
strncpy(my_data.field1, getData(field_keys[0]), sizeof(my_data.field1));
strncpy(my_data.field1, getData(field_keys[1]), sizeof(my_data.field2));
strncpy(my_data.field1, getData(field_keys[2]), sizeof(my_data.field3));
Of course, this is a simplification, and more things are going on in each assignment. The point is that I would like to represent the mapping between keys and struct member in a constant structure, and use that to transform the last code in a loop. I am looking for something like the following:
struct data_t {
char field1[10];
char field2[20];
char field3[30];
};
typedef char *(data_t:: *my_struct_member);
const std::vector<std::pair<const char *, my_struct_member>> mapping = {
{ "FIRST_KEY" , &my_struct_t::field1},
{ "SECOND_KEY", &my_struct_t::field2},
{ "THIRD_KEY", &my_struct_t::field3},
};
int main()
{
data_t data;
for (auto const& it : mapping) {
strcpy(data.*(it.second), getData(it.first));
// Ideally, I would like to do
// strlcpy(data.*(it.second), getData(it.first), <the right sizeof here>);
}
}
This, however, has two problems:
- It does not compile :) But I believe that should be easy to solve.
- I am not sure about how to get the
sizeof()
argument for using strncpy/strlcpy, instead of strcpy. I am usingchar *
as the type of the members, so I am losing the type information about how long each array is. In the other hand, I am not sure how to use the specificchar[T]
types of each member, because if each struct member pointer has a different type I don't think I will be able to have them in astd::vector<T>
.
As explained in my comment, if you can store enough information to process a field in a mapping, then you can write a function that does the same.
Therefore, write a function to do so, using array references to ensure what you do is safe, e.g.:
And then simply, instead of your
for
loop:Note that the amount of lines is the same as with a mapping (one per field), so this is not worse than a mapping solution in terms of repetition.
Now, the advantages:
Easier to understand.
Faster: no memory needed to keep the mapping, more easily optimizable, etc.
Allows you to write different functions for different fields, easily, if needed.
Further, if both of your strings are known at compile-time, you can even do:
Which will be always safe, e.g.:
Which has even more pros:
Way faster than any
strcpy
variant (if the call is done in run-time).Guaranteed to be safe at compile-time instead of run-time.