C语言 如何简单地访问结构内部联合中的数据?

6qqygrtg  于 2023-02-07  发布在  其他
关注(0)|答案(2)|浏览(103)

下面是我声明的类型:
(我也声明了t_spheret_cylindert_triangle

typedef struct  s_intersection{
  double       t1;
  double       t2;
  int id;
  union {
    t_sphere sph;
    t_cylinder cyl;
    t_triangle tri;
  } u;
} t_intersection;

当我在某些代码中使用交集结构时,是否有一种方便的方法来引用联合体中的成员?
例如,假设我想写一个函数,根据它所包含的geometric_figure的类型,它的行为会有所不同,我必须这样做吗?

if (geometric_figure_id == SPHERE_ID)
    // I know I will have to refer to p->u with p->u.sph...
else if(geometric_figure_id == CYLINDER_ID)
    // I know I will have to refer to p->u with p->u.cyl...
else if (geometric_figure_id == TRIANGLE_ID)
    // I know I will have to refer to p->u with p->u.tri...

如果我有10个不同的geometric_figures类型在我的union里面呢?这感觉很沉重。
你有更优雅的解决方案吗?

t40tm48m

t40tm48m1#

假设我想写一个函数,根据它所包含的geometric_figure的类型,它的行为会有所不同,我必须这样做吗?
听起来其他语言对运行时多态函数调度的支持可能是你的问题的一部分,如果是这样,那么重要的是要认识到你在这里调度的不是任何对象的 * 类型 *,就像你通常在C++或Java中那样,而是一个整数的 * 值
如果您希望对一个整数的不同运行时值遵循不同的控制路径,那么除了编写一个流控制语句(通常为if/else if/elseswitch)来适当地指导控制之外,没有其他选择。

现在,如果你 * 是 * 在类型上调度,那么C确实提供了类型泛型表达式。在大多数情况下,这些表达式只在宏内部使用是有意义的:

#define VOLUME(x) _Generic((x), \
    t_sphere: 4 * PI * (x).r * (x).r * (x).r / 3, \
    t_cylinder: PI * (x).r * (x).r * (x).h, \
    t_cube: (x).edge * (x).edge * (x).edge \
)

在宏以外的上下文中,您已经知道了所涉及的类型,因此类型泛型表达式不会为您带来任何值得拥有的东西。
取决于您要应用多少宏魔法,有很多方法可以避免手工写出长的if/else if/else语句或长的switch语句。类型通用宏可能会在类似的事情中扮演一个角色。但是这样的操作过程很难很好地实现。我们更有可能以复杂宏堆栈的混乱维护噩梦而告终,而不是得到可以与手动编写的switch语句相媲美的东西。

  • 或者,嵌套使用三元运算符的复杂表达式可以被视为满足需要,但如果需要手动编写和维护,则使用这样的表达式是不现实的。
oalqel3c

oalqel3c2#

你有更优雅的解决方案吗?
说"更优雅"使它基于观点,所以我宁愿称之为替代解决方案,而不是"更优雅"的解决方案。
为了避免许多嵌套的if语句(或者一个大的switch语句),你可以添加一个函数指针,所以当你创建一个t_intersection的示例时,你也可以设置函数指针指向t_intersection的特定子类型所需要的函数。
下面是一个基于OP代码的示例,为了使其更简单,做了一些修改。

#include <stdio.h>

#define SPHERE_ID 0
#define CYLINDER_ID 1

double sph_calculation(void* p)
{
    puts("sph_calculation");
    int n = *(int*)p;        // Cast back to correct type
    double res = 1.0/n;
    return res;
}

double cyl_calculation(void* p)
{
    puts("cyl_calculation");
    float f = *(float*)p;      // Cast back to correct type
    double res = 1.0/f;
    return res;
}

typedef struct  s_intersection{
  double       t1;
  double       t2;
  int id;
  double (*calculation)(void*);   // Function pointer
  union {
    int sph;
    float cyl;
  } u;
} t_intersection;

int main(void)
{
    t_intersection m[2];

    m[0].id = SPHERE_ID;
    m[0].calculation = sph_calculation;     // Set function to be called
    m[0].u.sph = 2;

    m[1].id = CYLINDER_ID;
    m[1].calculation = cyl_calculation;     // Set function to be called
    m[1].u.cyl = 3.0;
    
    // Do the calculation for all types without a need for nested if-statements
    for (int i = 0; i < 2; ++i)
    {
        double x = m[i].calculation(&m[i].u);
        printf("%f\n", x);
    }
    
    return 0;
}

输出:

sph_calculation
0.500000
cyl_calculation
0.333333

相关问题