0

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;
Vincenzo Cosi
  • 173
  • 1
  • 12
  • 4
    That is just perverse. – Weather Vane Jul 19 '17 at 18:29
  • 1
    If **pone* points to one and **ptwo* points to two then *memcpy(one,two,sizeof(one));* should to it. – Arif Burhan Jul 19 '17 at 18:30
  • So you copy a pointer but not what it points to. Suppose you then `free` the pointer in the first `struct`. Doomed. – Weather Vane Jul 19 '17 at 18:31
  • 1
    Not really, not automatically. The typical workaround is to extract the common fields into a parent structure which may be embedded into both structures and copied. Or you may play nasty games with half-baked introspection to register each individual member's name, offset and type. Then write a function to copy matching fields. Or use code generation to preprocess the structure definitions and generate suitable copying code offline. – doynax Jul 19 '17 at 18:31
  • free should only be used in conjunction with malloc() , these are static structures. – Arif Burhan Jul 19 '17 at 18:35
  • 1
    use memcpy https://stackoverflow.com/questions/4931123/copying-one-structure-to-another – EsmaeelE Jul 19 '17 at 21:23

4 Answers4

4

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.

dbush
  • 205,898
  • 23
  • 218
  • 273
0

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)
0

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.

  • 1
    You are relying on the assumption that both structures have the same representation, which may be true in this particular case but is highly error prone in general. Furthermore, your initial suggestion violate the aliasing rule, so should not be used at all. – chqrlie Jul 08 '23 at 17:47
  • *I really don’t recommend `memcpy` because it uses `void *` which is worse than any cast.* Oooof. Instead you propose invoking undefined behavior by violating strict aliasing? – Andrew Henle Jul 08 '23 at 17:49
  • @chqrlie And if someone in the future were to add a field or otherwise rearrange things in either of the structures in the future... – Andrew Henle Jul 08 '23 at 17:51
  • 1
    @AndrewHenle: we are on the same page: field by field copy is the only recommended way and there is no generic way to let the compiler enumerate the fields as is possible in javascript and some other languages. – chqrlie Jul 08 '23 at 18:18
  • 1
    @AndrewHenle and chqrlie: Thank you for your comments, I have deepened my investigations on the subject. Indeed I thought that type aliasing wasn’t a problem when using it only to read into an object, and I hadn’t noticed the warning triggered by GCC. Well, I’ve just realized the question is more about “copying fields with the same name” than reinterpreting a struct, so my answer is a bit out of scope… Let it be fixed. – Sylvain Chiron Jul 10 '23 at 06:08
-2

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));
}
Jonathon S.
  • 1,928
  • 1
  • 12
  • 18
  • Why do you reimplement `memcpy`? – Daniel Kamil Kozar Jul 22 '17 at 20:51
  • You are relying on the assumption that both structures have the same representation, which may be true in this particular case but is highly error prone in general. – chqrlie Jul 08 '23 at 17:46
  • @chqrlie: It is not error prone, it is a design pattern. – Sylvain Chiron Jul 10 '23 at 06:09
  • @SylvainChiron: if it is a design pattern, why not give the structures an identical tag or at least an identical first member whose size you would pass to `memcpy()`. You should also try and come up with compile time validation of the design pattern, but I cannot think of a generic one to test for a common prefix or an identical sequence of field types. – chqrlie Jul 10 '23 at 06:56
  • @chqrlie: You’re right, using an identical first member is certainly the right construct to use. – Sylvain Chiron Jul 10 '23 at 07:11
  • @SylvainChiron: too bad one cannot make it an anonymous member and the concept of structure derivation for free. – chqrlie Jul 10 '23 at 07:55