在理論上似乎書籍sugest用C聲明ADT爲:ADT在C - 有或沒有指針?
struct some_structure;
typedef some_structure *some_structure_t;
而大多數代碼使用:
struct some_structure;
typedef some_structure some_structure_t;
我知道const
不與第一種樣式的工作。這是真正的圖書館不使用第一種方法的唯一原因嗎?有沒有其他的通知或建議?
在理論上似乎書籍sugest用C聲明ADT爲:ADT在C - 有或沒有指針?
struct some_structure;
typedef some_structure *some_structure_t;
而大多數代碼使用:
struct some_structure;
typedef some_structure some_structure_t;
我知道const
不與第一種樣式的工作。這是真正的圖書館不使用第一種方法的唯一原因嗎?有沒有其他的通知或建議?
您的意思是抽象數據類型?如果我從你的代碼snipsets中的語法錯誤中抽象;-),我認爲是的typedef
指針類型是皺眉,因爲const
和volatile
的問題。
順便說一句,您的代碼的另一個問題是您選擇的名稱。 _t
作爲結尾保留在POSIX中供將來使用。
只因爲這個?對於ADT,「volatile」真的有用嗎? 我不知道'_t'被儲存。然而,許多庫使用這個約定。你知道任何更安全的約定(但請不要「_T」)。 – 2010-08-17 13:44:51
@ dpc.ucore.info另一種方法是對類型使用大寫字母,即Some_Structure_func()函數的Some_Structure和小寫字母。 – quinmars 2010-08-17 13:55:32
@ dpc.ucore.info:這是很好的做法,一個庫被許多人用來選擇一個前綴,並堅持使用它在頭文件中使用的所有符號和/或在對象中導出。例如,對於POSIX線程,使用'pthread_'作爲符號,'PTHREAD_'作爲宏。 (他們再次也有'_t',因爲它是POSIX。) – 2010-08-17 15:23:53
我用
typedef struct some_s *some_t;
和地方事務我要麼使用const struct some_s*
或typedef const struct some_s *const_some_t
,但我想這是個人喜好的問題。
另一種類型的const的聲明是個好主意,謝謝。 – 2010-08-17 13:45:40
你是否以某種奇特的方式處理鑄造?承諾不改變對象的函數應該接受'some_t'來代替'const_some_t'。 – 2010-08-17 14:06:33
@ dpc.ucore.info:你不需要。只需將some_t傳遞給sig爲const_some_t的函數,不會發出警告(至少它不會在icc,gcc和pcc上)。 – hroptatyr 2010-08-17 14:18:46
我以前用第一種方式去,但是我發現我對於訪問結構成員所需的間接尋址級別感到困惑,於是我開始向指針類型添加後綴,例如,
typedef struct AStruct *AStructRef;
但後來我意識到我正在有效地重新創建*運算符以阻止我被隱藏*運算符所迷惑。所以,現在我採用第二種風格。
抽象數據類型對於像「對象」這樣的東西有效執行操作很有用。
如果可以,在C中,完全避免使用「typedef」關鍵字。它掩蓋了真正發生的事情。作爲初學者,我建議你在任何你想使用typedef的地方都明確輸入struct AStruct
。
從那裏你可以通過聲明一個函數,該函數將一個指向「抽象數據類型」(或對象,我喜歡思考)的指針作爲第一個參數,對你的「抽象數據類型」執行一個「動作」然後是正常參數。
例如
int some_func(struct AStruct *pObject, int param1, int param2) {
if ((param1 < 0) || (param2 < 0))
return(0);
pObject->val = param1 + param2;
return(1);
}
然後使用:
#include <stdio.h>
int main(void) {
struct AStruct myObject;
if (some_func(&myObject, 10, 12)) {
printf("Processed: %d\n", myObject.val);
} else {
printf("Failed\n");
}
return(0);
}
+1第二個建議是爲了避免爲了方便而避免'typedef'結構。在'name_t'上面寫'struct name'只是瑣碎的工作。 OP注意到,保留數據類型爲'struct'的清晰指示可以幫助防止'const'出現問題。被迫寫'struct name *'而不是'name_ptr_t'也避免了JeremyP在他的回答中提到的一些間接混淆(指針顯然明顯地被聲明爲這樣)。 – bta 2010-08-17 16:21:35
這取決於什麼其他人的代碼將與這些類型做。由於磁帶庫的用戶,如果我認爲some_structure_t是一個結構,而不是一個指向一個結構,我可能會做這樣的事情:
some_structure_t *p;
p = malloc(sizeof *p);
memcpy(p, &another_p, sizeof *p);
也許這是我的背景,作爲一個嵌入式的程序員,但我想在我使用它的代碼中瞭解有關some_structure_t
的更多信息。即使它是一個真正的抽象類型,並且它只被用作最終用戶代碼中的參數或返回值,但您仍然必須在支持該類型的庫中處理它。如果我看到了下面的代碼,我會做恍然大悟:
some_structure_t some_function(some_structure_t foo)
{
some_structure_t retval;
retval = malloc(sizeof *retval); // assigning pointer to struct?
retval->member = foo->member; // using -> instead of .?
return retval; // returning potentially large structure on stack?
}
也許這是最大的一個 - 從一個some_structure_t
複製到另一個。如果是int
或float
或struct
,則編寫foo = bar
將進行復制。如果some_structure_t
被定義爲指向結構體的指針,則foo
和bar
指向同一個對象。也許這就是你想要的,但對我來說似乎有風險。
我不知道MISRA有沒有關於指針的typedefs的說法。
準確地說 - 在C中被認爲是不好的風格來隱藏類型是指針的事實,因爲類型的用戶無論如何都需要知道這一點。因此標準庫提供了'FILE *'。 – caf 2010-08-18 03:06:22
所以看起來 - 感謝所有好的答案 - 第二種風格(顯式指針)更實用。非常感謝您的幫助。 – 2010-08-19 08:03:52