Vincenzo Cosi
Vincenzo Cosi

Reputation: 187

How to copy the content of a structure​ in another structure in C

I have a C program where I have two structures

struct one{
  int a;
  int b;
  char *s;
  int c;
};

struct two{
  int a;
  int e;
  char *s;
  int d;
};

Is possible to write a function that copies the values of the variables with the same type and name from struct one to struct two? For example, in this case the function should do this

two.a = one.a;
two.s = one.s;

Upvotes: 0

Views: 845

Answers (4)

Sylvain Chiron
Sylvain Chiron

Reputation: 290

If it is really a matter of “copying fields having the same name”, C and (as far as I know) C++ have no dedicated shorthand. In the case of C, field names have no importance and the language has no (automatic) reflection capabilities. What matters is addresses, and field names actually are just ways to refer to particular addresses with a particular type in your struct.

So you may just have a function that uses a macro:

inline void one2two(struct one const * one, struct two * two)
{
    #define copy(field) two->field = one->field;
    copy(a) copy(s) // copy(whatever)
}

It will work even if the field types are different, using implicit casts, e.g. if one->a is of type int and two->a is of type double.

Well, a better design is simply to use a common struct inside your two structs:

struct zero {
    int a; char * s;
};
struct one {
    struct zero z;
    int b, c;
};
struct two {
    struct zero z;
    int e, d;
}

struct one one = { /* ... */ };
struct two two;
two.z = one.z; // sure, no problem

If you really want to be able to access the fields a and s directly, without writing z. all the time, you can use an anonymous member of union type (valid since C11):

struct one {
    union {
        struct zero z;
        int a; char * s;
    };
    int b, c;
};

The title of your question: “How to copy the content of a structure​ in another structure in C,” and your example with completely compatible structs (with fields of the same type and the same name having the same addresses), actually inspire another subject: reinterpretation (or type-punning) of the struct.

Copying the whole contents of compatible structs

In C++, the only highly reliable way seems to be to use memcpy.

C offers more guarantees for reinterpretation, as known as type-punning. As your structs have compatible types, you can use a pointer cast:

struct one {
  int a, b; char * s; float f;
};
struct two {
  int a, b; char const * s; float volatile f;
};

struct one one = { /* ... */ };
struct two * twoPtr = (struct two *)&one;
// or
struct two two = *(struct two *)&one;

I am getting a warning on the last line with gcc -O2 -Wall (using GCC 13.1.1) but it is apparently wrong.

Using twoPtr won’t trigger a copy of the struct. Using two (the last line) should imply a copy, but if you don’t modify one subsequently, it will probably be removed by optimizations. Note that dereferencing a pointer to a struct to access one of its fields also has a cost.

The copy might not be as deep as with memcpy because it could skip unused bytes i.e. paddings. In the above example, on a x86_64 machine, there are 4 unused bytes at the end of the struct, because sizeof(one.s) == alignof(one.s) == 8 and sizeof(one.f) == 4, and the end of a struct should be a possible start for another instance of the same type. Let’s have:

struct one ones[2];

Then by blocks of 4 and arbitrarily starting from 00, hexadecimal addresses will be as such:

00   ones[0].a
04   ones[0].b
08   ones[0].s
0C
10   ones[0].f
14
18   ones[1].a
2C   ones[1].b
30   ones[1].s
34
38   ones[1].f
4C

To me, such casts are really much better than using memcpy because the latter uses void * which is meant to be unsafe. If using only non-void * casts, a well-designed compiler should warn you if your types are not compatible, for instance.

Such casts may be used to implement inheritance for instance. GLib apparently uses it for its object system; I am able to see it in /usr/include/glib-2.0/gobject/gtype.h. And then you have many macros such as GTK_BOX() or GTK_WINDOW() in GTK, which themselves invoke G_TYPE_CHECK_INSTANCE_CAST() from the GLib. With GTK, you must constantly use such macros to call functions on your GTK objects.

This is ugly. I presented it first because it looks like people often have that kind of solutions in mind, and also because it is a (readable) one-line solution to your problem. But C actually offers a so much beautiful construct to handle your case: unions.

union one_or_two {
    struct one one;
    struct two two;
};

struct one one = { /* ... */ };
union one_or_two one2two = { .one = one };
struct two two = one2two.two;
// or
struct two two2 = (union one_or_two){ .one = one }.two;

In theory (i.e. without optimizations) this should imply 2 copies (you could use pointers to just copy addresses instead). If you really often need such interoperability between two structs, you should probably always conceive them very closely and provide the union in a header file. Note that you can also have a one-line solution if you want:

struct two two3 = (union { struct one one; struct two two; }){ .one = one }.two;

This is not perverse at all. Yes, reinterpretation is quite an advanced subject, but it is not an uncommon practice, and its availability empowers the C language which may not be so famous without it. The most common use of C unions is for implementing variants (see e.g. C++17’s std::variant). Another use is reinterpretation.

Because you know that you generally shouldn’t use casts and because you are afraid of pointers (or at least you know that they make the work more complicated), get used to C unions.

Upvotes: 1

Jonathon S.
Jonathon S.

Reputation: 1980

In theory you could do this with a simple block copy function for your example above using the code below if you are certain that your compiler sequences the structure as sequenced in its type definition. However, I don't think it's a great idea. Block copy would be safer with two data structures of the same type as defined in one of the answers proposed above.

Example using block copy function:

void main(void)
{

    struct one{
        int a;
        int b;
        char *s;
        int c;
    };

    struct two{
        int a;
        int e;
        char *s;
        int d;
    };

    // Place code that assigns variable one here

    memcpy(&two, &one, sizeof(one));
}

Upvotes: -2

Michal Butterweck
Michal Butterweck

Reputation: 438

You may write function macro like this:

#define CAT(A, B) A ## B
#define ARGS_ASSIGN(N, L, R, ...) CAT(_ARGS_ASSIGN, N) (L, R, __VA_ARGS__)
#define _ARGS_ASSIGN1(L, R, M0) L.M0 = R.M0;
#define _ARGS_ASSIGN2(L, R, M0, M1) L.M0 = R.M0; L.M1 = R.M1;
/* ... define sufficiently more */

and use in such way:

ARGS_ASSIGN(2, two, one, a, s)

Upvotes: 0

dbush
dbush

Reputation: 223917

There's no way to automatically grab fields of a given name from a struct. While you could do something like this in Java with reflection, it can't be done in C. You just need to manually copy the relevant members.

Upvotes: 4

Related Questions