2016-06-27 36 views
4

我正在爲我的hashmap數據結構設計一個迭代器接口。目前的設計是這樣的:不定義的不透明結構

// map.h 
typedef struct map_iterator map_iterator; 

// map.c 
struct map_iterator 
{ 
    // Implementation details 
}; 

// client.c 
map *m = map_new(); 
map_iterator *it = map_iterator_new(m); 
void *key, *value; 
while (map_iterator_next(it, &key, &value)) { 
    // Use key, value 
} 
map_iterator_free(it); 

然而,這需要iterator對象堆分配,並在客戶端必須記住釋放迭代他們完成時。如果我讓map_iterator_new返回堆棧上的迭代器,代碼如下:

// map.h 
typedef struct map_iterator 
{ 
    // Implementation details 
}; 

// client.c 
map *m = map_new(); 
map_iterator it = map_iterator_new(m); 
void *key, *value; 
while (map_iterator_next(&it, &key, &value)) { 
    // Use key, value 
} 

然而,這需要我提供map_iterator結構到客戶端代碼(否則我得到一個不完整的錯誤類型)的定義。我想隱藏這個定義,只提供聲明。

有沒有辦法達到這個目的?本質上,我正在尋找一種方法來告訴客戶端代碼「這個結構佔用X字節,因此您可以將它分配到堆棧上,但我不會告訴您如何訪問其成員」。

編輯:只有標準C! (沒有編譯器擴展/特定於平臺的功能)

+0

迭代器中的「實現細節」下面是什麼? – 2501

+0

@ 2501迭代器狀態,例如指向hashmap,當前存儲分區索引,修改計數等。 –

+1

我不認爲提供一個指向你的迭代器的指針,然後釋放它是一個問題。許多庫,如curl等也提供了這樣的接口。我寧願使用第一個選項而不使用第二個選項。 – ckruczek

回答

-1

有一個叫做alloca的函數,它在調用者的堆棧上保留內存。因此,您的代碼可能如下所示:

// map.h 
typedef struct map_iterator map_iterator; 
extern int map_iterator_size; 
// map.c 
struct map_iterator 
{ 
    // Implementation details 
}; 
int map_iterator_size = sizeof(struct map_iterator); 
// client.c 
map *m = map_new(); 
map_iterator *it = alloca(map_iterator_size); 
map_iterator_new(m, it); 
void *key, *value; 
while (map_iterator_next(it, &key, &value)) { 
    // Use key, value 
} 
+0

謝謝,但我忘了提及我正在尋找嚴格符合C99標準的解決方案,對此感到抱歉。 –

+0

鑑於其參與堆棧損壞漏洞的歷史,'alloca'是您應該永遠不會想到的那些函數之一。此外,這與API設計很少有關,因爲這是API用戶編寫的錯誤/選擇。最後,不完整的類型沒有'sizeof()'。 –

+0

我沒有看到'alloca()'和直接將對象直接放在堆棧之間的任何區別(從堆棧腐敗的角度來看)。 'sizeof'是在完全定義的地方計算出來的。 – nothrow

0

使用序列化。

您始終可以將T的對象複製到一個unsigned char數組,然後返回到T類型的對象。該對象將與原始對象相同。 T可以是任何對象類型,並且這可以用自動存儲持續時間(堆棧)來完成:

int value = 568; 
unsigned char store[sizeof(int)]; 
memcpy(store , &value , sizeof(int)); 
int other; 
memcpy(&other , store , sizeof(int)); 
assert(other == value), 

這可以是(AB)用於隱藏來自用戶的執行情況。定義兩個結構,一個定義實際實現並且對用戶不可見,另一個結構可見並且只包含適當大小的無符號字符數組。

implementation.c

#include "implementation.h" 

struct invisible 
{ 
    int element1; 
    char element2 
    float element3; 
    void** element4; 
}; 

_Static_assert(sizeof(struct invisible) <= VISIBLE_SIZE); 

struct visible New(void) 
{ 
    struct invisible i = { 1 , '2' , 3.0F , NULL }; 
    struct visible v = { 0 }; 
    memcpy(&v , &i , sizeof(i)); 
    return v; 
} 

void Next(struct visible* v) 
{ 
    struct invisible i = { 0 }; 
    memcpy(&i , &v , sizeof(i)); 
    i.element1++; //make some changes 
    const int next = i.element; 
    memcpy(&v , &i , sizeof(i)); 
    return next; 
} 

implementation.h

#define VISIBLE_SIZE 24 //make sure it greater or equal to the size of struct invisible 
struct visible 
{ 
    unsigned char[VISIBLE_SIZE]; 
}; 

struct visible New(void); 
int Next(struct visible* v); 

user.c的

#include "implementation.h" 

void Func(void) 
{ 
    struct visible v = New(); 
    while(1) 
    { 
     const int next = Next(&v); 
     if(next == 10) 
     { 
       break; 
     } 
     printf("%d\n" , next); 
    } 
} 

此示例只涉及成員element1。在真正的實現中,您可以自由修改不可見的結構。