2013-05-16 127 views
2
#include<stdio.h> 
#include<stdlib.h> 

void function(void *i, void *j); 

struct mystruct { 
    int a; 
    int b; 
} ; 

int main() 
{ 

    int a = 50; 

    struct mystruct s ; 
    s.a = 100; 
    s.b = 200; 
    function(&a, &s); 


} 


void function(void *i, void *j) 
{ 
    printf("Integer is %d\n", *i); 
    printf("Struct member 1 is %d\n", j->a); 
    printf("Struct member 2 is %d\n", j->b); 


} 

我上面的代碼。在編譯時,我得到以下錯誤,我明白我需要做些什麼來修復它們。void *函數形式參數的用法

voidstartest.c: In function function: 
voidstartest.c:27: warning: dereferencing void * pointer 
voidstartest.c:27: error: invalid use of void expression 
voidstartest.c:28: warning: dereferencing void * pointer 
voidstartest.c:28: error: request for member a in something not a structure or union 
voidstartest.c:29: warning: dereferencing void * pointer 
voidstartest.c:29: error: request for member b in something not a structure or union 

這就是我需要做什麼來修復錯誤:

printf("Integer is %d\n", *(int*)i); 

printf("Struct member 1 is %d\n", ((struct mystruct *)j)->a); 

printf("Struct member 2 is %d\n", ((struct mystruct *)j)->b); 

問題:

  1. 如果我必須修復錯誤,我上面描述的方式不說意味着我必須事先知道我發送給函數的指針類型?我覺得這是一個非常嚴格的要求。不是嗎?

  2. 某些庫函數有void形式的正式參數(例如qsort)。他們的實現如何知道指針的正確類型是什麼,這樣他們就可以解引用它來處理實際數據(指向它)?

回答

5
  1. 是。這意味着你不能以類型不可知的方式編寫函數,因此需要重新考慮你的設計。當與void*一起工作時,通常會寫一個模板函數,並向用戶請求函數指針,指向知道該類型的函數並執行基本操作。

  2. 它們的實現不。他們還以上述相同的方式向您詢問函數指針或大小參數。

+0

是的我看到qsort.c將基礎轉換爲char *,然後使用一個數組元素的大小,並且元素的數量做指針算術以伸出到其他數組元素以選擇哪些要比較的算法實現。 http://forums.devshed.com/c-programming-42/teacher-wants-source-code-of-qsort-function-233585.html – abc

5

一些庫函數有正式的說法爲void *也(如快速排序)。他們的實現如何知道指針的正確類型是什麼,這樣他們就可以解引用它來處理實際數據(指向它)?

因爲你還提供了一個比較函數,它有兩個空指針並返回比較的結果:

void qsort(void *base, size_t nmemb, size_t size, 
      int(*compar)(const void *, const void *)); 

在這種功能,就可以把空指針的指針的實際類型陣列元素,然後執行任何你想要的操作

int compare_your_structs(const void *first, const void *second) 
{ 
    const struct mystruct *first_struct = (struct mystruct *)first; 
    const struct mystruct *second_struct = (struct mystruct *)second; 
    /* sort by the "a" field only */ 
    return first_struct->a - second_struct->a; 
} 
1

C是靜態類型的。一個C程序通常不能在運行時推導出指針指向的對象的類型,無論它是一個空指針還是其他類型的指針。它相信你不要通過將指針指向與他們自己聲明的類型不同的對象來濫用指針。動態類型語言在提供這種額外功能時通常會產生開銷。

qsort不需要知道其void指針參數指向的對象的類型。它知道它們的大小,並且提供了一個比較函數,預計這個函數將被寫入來比較所討論類型的對象。

+0

是的,我看到qsort.c將基礎強制轉換爲char *,然後使用一個數組元素的大小和元素的數量做指針算術以達到其他數組元素,用於選擇要爲算法實現比較哪些元素。 http://forums.devshed.com/c-programming-42/teacher-wants-source-code-of-qsort-function-233585.html – abc

0

庫函數可以處理多種不同的方式。例如,qsort要求用戶提供一個函數指針,它是爲特定類型編寫的。這樣,用戶只需要知道類型,但qsort沒有這些信息。

其他功能,如memcpy,接受void*爲方便起見。實際上,由於memcpy是一個按字節的副本,它將參數轉換爲char*,因此它可以在字節級別上工作。

也可以編寫一個類似於printf的函數,該函數接受一個標識其參數類型的字符串。類似地,va_arg宏(用於處理可變參數)需要一個類型參數,例如, va_arg(list, int)。雖然printfva_arg不適用於void*(我認爲?),但他們面臨同樣的問題,因爲va_list是無類型的。所以這些概念也可用於在void*上運行的功能。