【问题标题】:C - Cast void pointer to structure dynamicallyC - 将 void 指针动态转换为结构
【发布时间】:2016-11-10 10:08:57
【问题描述】:

我想根据变量的值将指针转换为两个结构之一。我正在尝试这个,但它不起作用 -

struct typeA
{
     int a;
     int x;
}
struct typeB
{
     int b;
     int a;
     int x;
     int z;
}


int band=1;
void *ptr;

if(band == 1)
            ptr = (struct typeA *)malloc(sizeof(struct typeA));
else if(band == 2)
            ptr = (struct typeB *)malloc(sizeof(struct typeB));

printf("A:%d",ptr->a);//error: structure type required instead of void

最好的方法是什么?

编辑:添加结构定义和错误(在代码 cmets 中)以使其更有意义。

【问题讨论】:

  • C 中不需要强制转换。(同样ptrvoid *)请解释“不工作”。
  • 我投了反对票,因为你说你的代码不起作用,但你没有说为什么,编译器给你的错误或警告是什么。修改您提供此信息的问题,我将删除我的反对票。
  • 停止投射malloc(),但给ptr一个真实的类型。如果确实有充分的理由让ptr 成为void * 那么为什么不分配两个大小中的较大者呢?而且,咳咳,“它不起作用” 是对您的问题的糟糕描述。包含错误消息!
  • 好吧,那行不通。编译器需要知道ptr 指向什么类型。我想你可以在每次使用它时投射ptr,但哇,那会很难看。严格来说,您必须取消引用指向其原始类型的指针。 (然而,这是一个被广泛忽视的规则。)无论如何,这是高级 C,现在,声明两个具有两种不同类型的指针。
  • if(band == 1){ ptr = malloc(sizeof(struct typeA)); /* ...set a... */ printf("A:%d\n", ((struct typeA*)ptr)->a); }else if(band == 2){ ptr = malloc(sizeof(struct typeB)); printf("A:%d\n", ((struct typeB*)ptr)->a); }

标签: c struct void-pointers


【解决方案1】:

如果你不需要知道你有什么类型的结构,使用

if(band == 1)
        ptr = malloc(sizeof(struct typeA));
else if(band == 2)
        ptr = malloc(sizeof(struct typeB));

malloc 的返回类型已经是void *

然而,这是一个code smell --- 你真的在你创建它之后不需要知道结构的大小或类型吗?我会重新考虑一下你的设计。

编辑根据您发布的其他代码,我强烈推荐一种新方法。例如typeAtypeB中的字段顺序不同,所以ptr->a无论ptr的类型如何都无法同时引用它们。如果您坚持使用纯 C,请考虑一个具有 axstruct 以及指向具有 bz 的单独结构的可选指针。或者,对所有内容都使用typeB,然后删除typeA

【讨论】:

    【解决方案2】:

    您不应该转换malloc 的结果,因为这样做会掩盖其他问题。由于类型不匹配,它也会在此处引起警告。

    去掉演员表,你应该不会收到任何警告。

    编辑:

    错误是因为您试图取消引用 void *,这是非法的。

    不要使用一个变量,而是使用两个(每种类型一个)并将另一个设置为 NULL。或者,如果您知道 void * 指向的数据类型,您可以将其转换为正确的类型,然后取消引用它。

    【讨论】:

    • 类型不匹配,但 void* 是最通用的指针类型,因此将指向任何其他类型的指针分配给 void* 应该不是问题,或者我是错误的?不是反对者。
    【解决方案3】:

    这里的转换不会给你带来任何好处,因为每次转换的结果都会立即转换为ptr 的类型。无论哪种方式,指向malloc-ed 对象的指针最终都存储在ptr 中,而ptr 恰好有一个与malloc 返回的完全匹配的静态类型。唯一不同的行为是malloc-ed 区域的大小。

    您的逻辑可以简化为单行:

    void *ptr = malloc(band == 1 ? sizeof (struct typeA) : sizeof (struct typeB));
    

    需要更多的上下文来判断这对于周围的代码是否是一种好的方法,或者更严格的“类似 OOP”的方法是否会更好,或者在两个单独的代码片段之间进行简单切换是否有效在不同的结构上。

    如果没有额外的强制转换,实际的对象是不能作为typeAtypeB访问的,所以可以想象后面会出现很多丑陋的代码,比如

    if (band == 1)
       do_this_A_version((struct typeA *) ptr)->foo, x);
    else
       do_this_B_version((struct typeB *) ptr)->bar, y);
    

    有一些很好的方法可以避免这种事情,超出了这个问题的范围。

    【讨论】:

      【解决方案4】:

      [ EDIT ] OP 被编辑后代码 sn-p 更新。

      这是对实际问题的猜测,但也许以下是 你在追求。

      struct typeA
      {
          int a;
          int x;
      };
      struct typeB
      {
          int b;
          int a;
          int x;
          int z;
      };
      
      union { struct typeA *A; struct typeB *B; } ptr;
      if(band == 1)
          ptr.A = malloc(sizeof(struct typeA));
      else if(band == 2)
          ptr.B = malloc(sizeof(struct typeB));
      
      /* ... later on ... */
      
      if(band == 1)
          printf("A::a = %d", ptr.A->a); /* use ptr.A as a struct typeA pointer */
      else if(band == 2)
          printf("B::a = %d", ptr.B->a); /* use ptr.B as a struct typeB pointer */
      

      【讨论】:

        【解决方案5】:

        正如其他人所建议的那样,您可能需要更改您的设计,因为它存在一些缺陷。

        但是,要解决您遇到的编译错误,您可以执行以下操作:

         printf("A:%d",(band == 1) ? ((struct typeA *)ptr)->a : ((struct typeB *)ptr)->a);
        

        您收到错误是因为您尝试从void * 访问成员a,而您却这样做了(ptr->a)。

        您需要明确表示ptr 指向struct typeAstruct typeB

        【讨论】:

          猜你喜欢
          • 2023-03-26
          • 1970-01-01
          • 1970-01-01
          • 2022-01-17
          • 1970-01-01
          • 2023-02-26
          • 2011-02-15
          • 2012-11-21
          • 1970-01-01
          相关资源
          最近更新 更多