簡體   English   中英

C無效指針問題

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM