【问题标题】:Copying variables of one inner struct to other inner struct using a function that takes address of one inner struct as a parameter使用将一个内部结构的地址作为参数的函数将一个内部结构的变量复制到另一个内部结构
【发布时间】:2014-10-06 22:03:54
【问题描述】:

我有一个看起来像这样的复杂结构。

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;

我使用了一个函数,它将“struct c”的地址作为参数。现在我希望这个函数将“struct c”的值复制到“struct b”。我在 main 函数中进行的函数调用可能如下所示。

copy_val(&z.y);

现在,我该如何定义 copy_val?有什么建议? 如果我定义了一个 struct c 类型的指针,如下所示它不起作用。

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;
}

【问题讨论】:

  • 尝试一些东西,分享它,并展示你尝试过的东西,然后如果你有问题,我们可以讨论它。所以不是让我们编写您的代码的地方。我会说一个从一个复制到另一个的函数将需要传递给它的两个内部结构地址,如果你坚持传递内部结构..
  • 你不是说要从c结构复制到b结构吗?
  • 是的,这是一个错字...我的意思是从 c 复制到 b...@JoachimPileborg
  • 如果结构 b 和结构 c 相同,则只需定义一个结构并将其用于两个不同的变量。那么只需将一个变量分配给另一个变量即可。
  • 我也不会指望 tmp 指针的递减来让你进入 struct b 。不知道编译器可能对 struct a layout 做了什么。

标签: c struct structure


【解决方案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】:

你说你想取一个结构成员的地址,并以此为基础引用其他成员。

这有点不确定;很自然的做法是获取要与其成员一起工作的顶级结构的地址,即struct a

也可以简化:

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

完成后,您可以这样做:

z.x = z.y;

复制struct b类型的整个值。

【讨论】:

    【解决方案3】:

    如果您像这样通过copy_val(&amp;z.y);,您将无法以正确的方式捕获它,因为您在结构中具有结构。所以尝试传递整个结构并复制它-

    copy_val(&z);
    

    试试下面的代码-

    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;
    }
    

    【讨论】:

      【解决方案4】:

      根据 C 标准第 6.2.7 p.1 节(强调我的),您认为 bc 是同一类型的假设无效:

      ...如果对中的一个成员声明了名称,则声明另一个成员 同名

      由于结构使用不同的成员名称,它们被认为是兼容的,因此你的假设是无效的。

      此外,即使它们是 exact 相同的类型,tmp=tmp-1; 语句也是无效的:虽然 sizeof(struct b) 可能 报告类似 8 的内容,但这并不表示两个结构之间的填充为零。

      相反,您应该使用offsetof 宏来获取z 的地址,给定z.y 的地址:

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

      但是请注意,这可能会破坏别名假设,因为指向 z 的对象的一部分也被 y 指向,但指针不兼容。

      【讨论】:

      • 这不会破坏别名假设,z 所指向的,一个struct a 对象(所以在*z 声明和有效类型匹配)。但我认为,这是越界访问:(char *)addr 是一个指向sizeof *addr 大小的数组的指针,指向它的第一个字节。带有边界检查(允许)的实现可能会抛出异常。
      • @mafso 实际上,因为addr 被假定为struct a 内的struct c 的地址,addr 是指向 中间 的指针sizeof(struct c) 大小的数组,它不是 OOB。考虑char y[100] = ...; char *z = &amp;y[20];,那么z[-15] 不是OOB(因为它指的是y[5])。
      • 您的示例与 IMO 不同(正如您所说,已定义)。我的担忧有点难以描述,我认为你的回答是可以的(除了这里肯定没有混叠问题)。您是否有兴趣就此展开讨论,也许是在聊天中?
      • @mafso 当然,但接下来的几个小时我很忙
      • @mafso 好的,我已经在 chat.stackoverflow.com/rooms/59294/… 聊天了
      【解决方案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;
      }
      

      【讨论】:

      • 这实际上是 OP 所描述的尝试,但没有奏效。 c_pointer - 1 的使用无效。
      • OP 代码不起作用,因为他的 tmp 指针是 struct c * 类型。我确实同意使用 offsetof 是一个更好的答案,但是我在我的机器上测试了我的代码,它确实有效。不过,我不会使用它。
      • 仅仅因为它可以在您的计算机上运行并不意味着它不一定正确。毕竟,未定义的行为包括按预期工作。
      猜你喜欢
      • 2018-09-11
      • 1970-01-01
      • 2016-05-21
      • 2022-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-14
      相关资源
      最近更新 更多