[英]C Void pointer question
我在C(嵌入式編程)中有grep函數,它將void指針作為參數。 該函數需要能夠處理不同類型的變量,如字符整數和長整數。 我如何編寫函數代碼,以便它可以自己弄清楚我傳遞的是什么類型的變量? 我不知道這是否可行。 謝謝
即。
void grep( void *t )
{
if( t == char )
{
do this
}
if( t == int )
{
do that
}
...
}
任何准確性都無法做到。 例如,4字節整數可以很容易地解釋為字符串。 例如,空終止字符串“ABC”將與整數值1094861568相同(取決於字節順序)。
Void指針只包含存儲器中存儲數據的位置。 您無法從中推斷出任何類型信息。 但你可以做的是,將兩個參數傳遞給你的函數,一個用於類型,另一個用於指針。
如果可以使用C ++,則可以創建一組重載的輔助函數來提供類型信息。
這在C中是不可能的。您必須明確指出參數的預期類型。 您將必須傳遞第二個參數或傳遞具有類型信息作為參數的union或struct。
您基本上是在詢問如何在C中進行內省 。不幸的是,這不是受支持的功能。
相反,你可以像@ anand.arumug指出的那樣使用像grep_char這樣的函數。 或者(如果可能的話)您可以轉移到C ++並使用其功能重載功能。
直接回答:這是不可能的。 此外,您應該避免編寫這樣的超級函數,這些函數可以在多種類型上運行2,而您無法真正概括代碼並應用多態。 在C中,這通常涉及函數指針。 否則,編寫每個單獨類型的多個函數都沒有錯。 事實上,這應該優於超級功能。
這是一個基本的例子(不是很有用,但很簡單):
#include <stdio.h>
typedef int less_function(void*, void*);
struct foo
{
int data;
};
int foo_less(void* a, void* b)
{
struct foo* f1 = a;
struct foo* f2 = b;
return f1->data < f2->data;
}
int find(void* search_array, void* element, int num, int element_size, less_function* less)
{
int j = 0;
char* search_pos = search_array;
for (j=0; j < num; ++j, search_pos += element_size)
{
// if current element == element to find
if (!less(search_pos, element) && !less(element, search_pos) )
return j;
}
return -1;
}
int main()
{
struct foo my_array[10] = { {0}, {1}, {2}, {3}, {4}, {5}, {6}, {123}, {7}, {8} };
struct foo search_element = {123};
// outputs 7
printf("%d\n", find(my_array, &search_element, 10, sizeof(struct foo), foo_less) );
}
在上面的代碼中,你可以看到我沒有像這樣的代碼:如果這個類型是一個整數,那么,如果它是一個浮點數,那么這樣做,如果它是一個struct foo對象,那么這樣做,等等我們依賴在函數指針上提供自定義行為,用於比較傳入的對象類型。
qsort也這樣做,是一個很好的例子。 它與上面的find函數非常相似,除了它的比較器不會根據第一個對象是否小於另一個而返回true / false:它就像strcmp並返回0,-1或+1。
我想你會發現這在C中是不可能的。
C ++有模板和重載,這是解決這類問題的好方法。
在普通的舊C中,您只需為每個需要處理的類型編寫不同的函數。
宏是C中的另一種選擇,但要考慮它是否值得為其他開發人員帶來的努力和困惑。
您可能想看看ioctl()
函數。 它采用指向內存的通用指針,並根據傳遞給函數的請求代碼對其進行不同的解釋。 如果沒有某種附加信息,您無法確定通用指針指向的內容,而ioctl()
函數則顯示了一種(相對簡單)的方法。
我能想到的唯一方法是將類型作為第二個參數傳遞,或者使用指針和枚舉的結構或指定類型的結構,並傳遞它而不是裸指針。 C沒有.net和Java這樣的內置元數據,甚至不是我所知道的RTTI的等價物。
這種多角色功能不是推薦的方法,因為很難捕獲編程錯誤和調試。 我建議為每個參數類型創建單獨的grep函數,並為任何共享的grep代碼邏輯調用這些函數。
如果你必須將無類型對象傳遞給函數,那么我建議你將它們包裝在一個用類型裝飾它們的結構中。 就像是:
struct {
enum TYPE { INT, CHAR, STRING } type;
void *object;
}
不可能。
您必須傳遞一個額外的變量來告訴函數輸入變量的類型。 但是我認為你可以使用上面建議的宏。 這樣你就可以將函數grep分解為3個子函數(如果我可以將它們稱為那么)。
如果您稍后傳遞任何其他數據類型,枚舉將更容易。 您可以在函數內部使用switch語句並對輸入數據執行操作。
enum TYPE( TYPE_1, TYPE_2, TYPE_3,TYPE_MAX}; /*Add other data types into this enum if need be */
請根據您的要求命名枚舉條目。
稍后您可以修改功能開關外殼並為其添加一個附加外殼。
如果你知道你將要處理的類型,那么你可以為每種類型定義一個grep函數,如:
grep_int(int* pi);
grep_char(char* pc);
grep_float(float* pf);
還要定義一個宏
#define GREP(T, TPTR_VAR) grep_##(TPTR_VAR)
所以像GREP(int, pi)
類的調用將被轉換為grep_int(pi)
正如Mark指出的那樣,這是不可能的,但你可以為你期望的類型制作重載版本。
編輯:更正,您可以創建類似的函數來處理不同的類型:
void grep_c( char *t )
{
do this
}
void grep_i( int *t )
{
do that
}
我最近寫的C ++太多了!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.