3

我在一个普通的 C (嵌入式项目,很少的内存)中工作,我有一个结构

typedef struct 
{
   int x;
   int y;
   int z;
   float angle;
   float angle1;
   float angle2;
} Kind1;

有些情况下我需要所有字段,有些情况下我只需要 x、y 和角度。

在 C++ 中,我将创建一个具有这 3 个字段的基类,从它继承另一个具有额外 3 个字段的类,并根据需要实例化一个或另一个。如何在纯 C 中模拟这种行为?

我知道我可以做出类似的东西

typedef struct 
{
   int x;
   int y;
   float angle;
} Kind1;

typedef struct
{ 
   Kind1 basedata;
   int z;
   float angle2;
   float angle3;
}  Kind2;

但随后我无法将指针传递给 Kind2 ,其中请求了指向 Kind1 的指针。

我知道可以对指针进行类型转换和偏移,我只是想知道是否有更好、更安全的方法。

4

6 回答 6

5

我知道可以对指针进行类型转换和偏移

不必要:

void foo(Kind1*);
struct Kind2
{ 
   Kind1 basedata;
   int z;
   float angle2;
   float angle3;
}

//...
Kind2 k;
foo(&(k.basedata));
于 2012-06-04T08:40:18.540 回答
2

下面的示例假定这些定义。

struct base { char c; } *a_base;
struct sub  { struct base b; int i; } *a_sub;

您的“示例”实际上是(最简单的)正确解决方案。

但随后我无法将指针传递给 Kind2 ,其中请求了指向 Kind1 的指针。

是的你可以。以下来自 C11 标准,但以前的修订版具有相同的保证[需要引用]。

n1570 6.7.1.1.15

...指向结构对象的指针,经过适当转换,指向其初始成员(或者如果该成员是位域,则指向它所在的单元),反之亦然。结构对象中可能有未命名的填充,但不是在其开头。

因此(struct base*)a_sub == &a_sub->b((struct base*)a_sub)->c == a_sub->b.c

因此,只要您的“超结构”是“子结构”的第一个成员,您就可以在通过引用访问时将一个视为另一个。基本上不要这样做。

void copy(struct base *from, struct base *to)
{
    *to = *from; // Oops, you just lost half your object.
}
于 2014-03-16T18:45:48.787 回答
2

你可以像在 C++ 中那样做:

struct Kind1
{
   int x;
   int y;
   float angle;
}

struct Kind2
{ 
   int z;
   float angle2;
   float angle3;
}

struct Kind
{
    Kind1 k1;
    Kind2 k2;
}
于 2012-06-04T08:38:40.633 回答
2

在纯 C 语言中是不可能的,该语言没有这样的特性。但是,您可以使用预处理器宏来简化类型转换和偏移。

于 2012-06-04T08:42:49.463 回答
0

One way that I can think of which will save not more than 2*sizeof(float) bytes.

struct Kind2
{ 
   int z;
   float angle2;
   float angle3;
}

struct Kind1
{
   int x;
   int y;
   float angle;
   struct Kind2 *k2;
}

here the whole saving will be based on how much memory the pointer eats.

Init the pointer only if it is needed.

于 2012-06-04T09:42:53.240 回答
0

在内存有限的情况下,通过声明两个不同的结构来保持理智:

struct Kind1
{
   int x;
   int y;
   float angle;
}

struct Kind2
{ 
   int x;
   int y;
   int z;
   float angle;
   float angle2;
   float angle3;
}

我曾经不得不编写使用联合和预处理器#define的代码,以使代码看起来更具可读性。然而,这很快就会导致疯狂。如果这两个结构实际上是作为子类处理的,那么重新排列字段是最不邪恶的:

struct Kind1
{
   int x;
   int y;
   float angle;
}

struct Kind2
{ 
   int x;
   int y;
   float angle;
   // extended data:
   int z;
   float angle2;
   float angle3;
}

只要它们与铸造一起小心使用。但是,如果出现任何问题,确实应该进行调试版本名称检查以证明一切都正确完成。

struct Kind1
{
   char variant[6];  // initialized to "kind1" 
   int x;
   int y;
   float angle;
}

struct Kind2
{ 
   char variant[6];  // initialized to "kind2" 
   int x;
   int y;
   float angle;
   // extended data:
   int z;
   float angle2;
   float angle3;
}

function_expecting_kind2 (struct kind2 *p)
{
     if (strcmp (p->variant, "kind2"))
           error ("function expecting kind2 got '%s' instead", p->variant);
     ...
}
于 2012-06-04T09:23:48.500 回答