【问题标题】:How do I return one of two types in C?如何在 C 中返回两种类型之一?
【发布时间】:2021-12-15 17:26:56
【问题描述】:

假设这段代码

typedef struct A {
    ...
} A;

typedef struct B {
    ...
} B;

// If it was TypeScript I would say `type uknown = A | B;`
uknown getAorB(int k) {
    if (k > 0) return (A){...};
    return (B){...};
}

该函数getAorB 应根据参数k 返回A 或B。好的,但是返回类型是什么,是否可以在 C 中实现?

【问题讨论】:

  • 调用函数如何知道返回了什么?
  • 可能是联合类型?
  • 编写两个函数,让调用者根据k传递的内容决定调用哪个。
  • 这应该解决的实际潜在问题是什么?为什么你需要一个函数来根据某个变量返回不同的类型?现在这非常像XY problem。请直接询问实际和潜在的问题,也许将此作为​​您考虑过的可能解决方案。
  • 在 C 中,这没有什么意义(如果可能的话——但事实并非如此),因为您需要以某种方式使用返回的值,例如通过存储在变量中。但是变量会是什么类型呢?

标签: c struct


【解决方案1】:

这样做的一种方法是使用另一个包含“类型”的结构 返回的结构。这可能看起来像这样:

#define STRUCTA 1
#define STRUCTB 2

typedef struct SUPER {
   int type;
} SUPER;    

typedef struct A {
   int type;
   ...
} A;

typedef struct B {
   int type;
   ...
} B;


SUPER* getAorB(int k) {

    if (k > 0) {
        A *a;
        a = malloc(sizeof(*a));
        a->type = STRUCTA;
        return (SUPER*)a;
    } 
    
    B *b;
    b = malloc(sizeof(*b));
    b->type = STRUCTB;
    return (SUPER*)b;
}

然后在调用函数中检查 SUPER 的类型并将其转换为适当的函数。

A *a;
B *b;

if (returnedSuper->type == STRUCTA) {
    a = (A*)returnedSuper;
}
else if (returnedSuper->type == STRUCTB) {
    b = (B*)returnedSuper;
}

【讨论】:

  • 这是一个非常低效的解决方案(malloc 可能非常昂贵)+ 它会增加很多麻烦,因为您需要在不需要时释放分配的内存。它还违反了严格的别名规则。当您看到指针转换时,请始终保持清醒。这是不良代码和潜在 UB 的标志。因此,IMO 这是一个非常糟糕的解决方案。
【解决方案2】:

使用联合。

typedef struct A {
    ...
} A;

typedef struct B {
    ...
} B;

typedef union
{
    struct A a;
    struct B b;
}A_OR_B;

// If it was TypeScript I would say `type uknown = A | B;`
A_OR_B getAorB(int k) {
    A_OR_B c;
    if (k > 0) c.a.member = something;
        else c.b.member = somethingelse;
    return c;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-17
    • 2021-03-22
    • 2014-12-24
    • 1970-01-01
    • 2021-11-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多