2012-06-04 49 views
3

我在一個普通的C(嵌入式項目,很少的內存)工作,我有一個結構如何繼承結構在一個普通的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。

我知道這是可能的類型轉換和偏移指針,我只是想知道是否有更好,更安全的方法。

+0

使用Kind1和Kind2的聯合 – RolandXu

+1

http://stackoverflow.com/q/10872130/905902的可能重複,包括語法錯誤。 – wildplasser

+0

@wildplasser:我錯過了這一個,很奇怪,我試着先搜索一下。 BTW,語法錯誤 - 你是什麼意思?這顯然是一種僞代碼。 – Flot2011

回答

5

我知道這是可能的類型轉換和偏移指針

不一定:

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

//... 
Kind2 k; 
foo(&(k.basedata)); 
2

你可以做到這一點就像你在C將++:

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

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

struct Kind 
{ 
    Kind1 k1; 
    Kind2 k2; 
} 
+0

該項目專用於嵌入式設備,整個過程就是爲了節省內存,否則我可以和Kind2一起生活。 – Flot2011

+0

刪除了我的評論,有點太晚了。謝謝。 – BigMike

+0

@ Flot2011:聽起來像是不成熟的優化,但您可以在任何給定的用例中使用Kind1,Kind2或Kind。 –

2

在純C語言中是不可能的,語言沒有這樣的功能。但是,您可以使用預處理器宏簡化類型轉換和偏移。

0

在內存有限的情況下,通過聲明兩個不同的結構保持理智:

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

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

我曾經工作它使用了工會和預處理#define s到使代碼代碼更具可讀性。但是,這很快就會導致瘋狂。如果兩個結構作爲一個子類實際處理,然後重新排列領域是最邪惡:

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); 
    ... 
} 
0

我可以想到的一種方法,它將節省不超過2 * sizeof(float)個字節。

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

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

這裏整個保存將基於指針吃掉多少內存。

只有在需要時才初始化指針。

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