João Rodrigues
João Rodrigues

Reputation: 63

C Language - Copy two different structure types

Is there any way to copy two different structure types, with similar content, without copying variable by variable?

For example, read a file, save to pessoa and copy to xpessoa assuming email is 'not defined'.

struct pessoa {
    char nome[50];
    char telefone[20];
    struct{
    int dia,mes,ano;
    }data_nasc;
};

struct xpessoa {
    char nome[50];
    char telefone[20];
    struct{
    int dia,mes,ano;
    }data_nasc;
    char email[50];
};

Upvotes: 1

Views: 235

Answers (3)

Ian Abbott
Ian Abbott

Reputation: 17513

If you cannot change the "extended" structure to include the "base" structure as its initial member, the only legal way to copy the whole "base" structure into the "extended" structure is to define a union containing both structure types as members.

Quoting C11 section 6.5.2.3 (Structure and union members) paragraph 6:

One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible. Two structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members.

So you can define a union containing members of type struct pessoa and struct xpessoa and access the common parts from either member:

union upessoa {
    struct pessoa p;
    struct xpessoa xp;
};

int somefunc(void) {
    union upessoa a = { .p = {"Fred", "555-5555", {1, 2, 3} };
    // This is legal because data_nasc is part of the common initial sequence
    return a.xp.data_nasc.ano;
}

In my experience, a lot of code ignores this requirement for the structures to be members of a union, and assumes that if any two structures share a common initial sequence, the common initial sequence can be copied between objects of the different structure types; but this results in undefined behavior - it might work, but it isn't portable.

Upvotes: 0

tgregory
tgregory

Reputation: 564

If for some reason you are not allowed to change either structure than, you could do something like this:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct pessoa {
    char nome[50];
    char telefone[20];
    struct{
    int dia,mes,ano;
    }data_nasc;
};

struct xpessoa {
    char nome[50];
    char telefone[20];
    struct{
    int dia,mes,ano;
    }data_nasc;
    char email[50];
};

int main() {
  struct pessoa p = {"John", "111-222", {1, 2, 3}};
  struct xpessoa xp = { .email = "[email protected]"};
  memcpy(&xp, &p, sizeof(p));
  printf("name: %s email: %s \n", xp.nome, xp.email);
  return 0;
}

However as @dasblinkenlight said, this would be a very dangerous approach, since it would require to manually track the both structures.

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 727127

An approach that is guaranteed to work is to embed the pessoa into xpessoa, like this:

struct xpessoa {
    pessoa p;
    char email[50];
};

This approach protects your code from undefined behavior in case pessoa layout is changed, because xpessoa no longer mirrors its layout.

Upvotes: 6

Related Questions