Copying variables of one inner struct to other inn

2019-09-06 01:30发布

问题:

I have a complex structure which looks like this.

struct a
{
  struct b
  {
    int b_inner_int;
    char b_inner_char;
  }x;

  struct c
  {
    int c_inner_int;
    char c_inner_char;
  }y;

}z;

I use a function, that takes address of "struct c" as an argument. Now I want this function to copy the values of "struct c" to "struct b". The function call that I make in the main function may look like this.

copy_val(&z.y);

Now, how do I define copy_val? Any suggestions? If i define a pointer of type struct c, like below it isn't working.

void copy_val(struct c *addr)
{
    struct c *tmp=addr;
    int tmp_int=tmp->c_inner_int;
    int tmp_char=tmp->c_inner_char;

    tmp=tmp-1; /** assuming that b and c are of same type and decrementing pointer by 1 takes to beginning of b **/

    tmp->b_inner_int=tmp_int;
    tmp->b_inner_char=tmp_char;
}

回答1:

#include <stdio.h>
#include <stddef.h>

struct a
{
  struct b
  {
    int b_inner_int;
    char b_inner_char;
  }x;

  struct c
  {
    int c_inner_int;
    char c_inner_char;
  }y;

}z;

void copy_val(struct c *addr){
    size_t offset_c = offsetof(struct a, y);
    size_t offset_b = offsetof(struct a, x);
    struct b *bp = (struct b*)((char*)addr - offset_c + offset_b);
    bp->b_inner_int = addr->c_inner_int;
    bp->b_inner_char = addr->c_inner_char;
}

int main(void){
    z.y.c_inner_int = 1;
    z.y.c_inner_char = '1';
    copy_val(&z.y);
    printf("%d, %c\n", z.x.b_inner_int, z.x.b_inner_char);
    return 0;
}


回答2:

You say that you want to take the address of a structure member, and reference other members based on that.

That's a bit iffy; the natural thing to do would be to take the address of the top-level structure whose members you want to work with, i.e. a struct a.

Also, it can be simplified:

struct a
{
  struct b
  {
    int b_inner_int;
    char b_inner_char;
  } x, y;
} z;

With that done, you can do just:

z.x = z.y;

to copy the entire value of type struct b.



回答3:

Your assumption that b and c are the same type is invalid, according to the C standard section 6.2.7 p.1 (emphasis mine):

...if one member of the pair is declared with a name, the other is declared with the same name.

Because the structs use different member names, they are not considered compatible, thus your assumption is invalid.

Further, even if they are the exact same type, the tmp=tmp-1; statement is not valid: while sizeof(struct b) may report something like 8, this does not mean there's zero padding between the two structures.

Instead, you should use the offsetof macro to get the address of z, given the address of z.y:

struct a *z = (struct a *)((char *)addr - offsetof(struct a, y));

Note, however, that this may break aliasing assumptions, as part of the object pointing to z is also pointed to by y, but the pointers are not compatible.



回答4:

If you pass like this copy_val(&z.y); you can't catch it in proper way because you have structure inside structure. so try to pass whole structure and copy it-

copy_val(&z);

Try the following code-

void copy_val(struct z *addr)
{
addr->x.b_inner_int= addr->y.c_inner_int;
addr->x.b_inner_char= addr->y.c_inner_char;
}


回答5:

include <stdio.h>

struct a
{
  struct b
  {
    int b_inner_int;
    char b_inner_char;
  }x;

  struct c
  {
    int c_inner_int;
    char c_inner_char;
  }y;

}z;

void copy_val(struct c *c_pointer)
{
    struct b *tmp = (struct b *) (c_pointer-1);

    tmp->b_inner_int = c_pointer->c_inner_int;
    tmp->b_inner_char = c_pointer->c_inner_char;
}

int main(int argc, char **argv)
{

    struct a test;

    test.y.c_inner_int = 32; 
    test.y.c_inner_char = 'A';

    copy_val(&test.y);

    printf("b inner int : %d\n", test.x.b_inner_int);
    printf("b inner char %c\n", test.x.b_inner_char);


    return 0;
}