2009-07-14 67 views
32

我遇到了下面的函數簽名,我想知道這個(省略號或"...")是否是某種多態性?在C中的參數列表中是什麼意思?

#include <fcntl.h> 
int fcntl(int fd, int cmd, ...); 

在此先感謝。

+4

公平的問題。 +1。有些人仍然認爲,簡單的問題並不適合,儘管權力表明他們是這樣。 – paxdiablo 2009-07-14 09:12:48

+0

我建議將問題的標題改爲「什麼是省略號(...)C:「 – 2009-07-14 09:26:18

+0

@Hosam:是的,它不是真的關於多態性...標題改變了。 – 2009-07-14 10:05:03

回答

8

不,那是「省略號」你看到沒有,假設你指的是聲明的...一部分。

基本上它說這個函數在指定的前兩個參數後面有一個未知數量的參數。

該函數必須以這樣一種方式編寫,以便知道該期待什麼,否則會產生奇怪的結果。

對於支持此功能的其他功能,請查看printf函數及其變體。

+1

此外,參數也有一個未知類型。所有你在函數中得到的是一個指向第一個參數的指針,你必須把它變成有用的東西 – 2009-07-14 11:08:58

2

我假設你指的是省略號(...)?如果是這樣,則表示將會有0個或更多參數。這就是所謂的可變參數,在STDARG.H定義

http://msdn.microsoft.com/en-us/library/kb57fad8.aspx

的printf使用此功能。沒有它,你將無法繼續添加參數到函數結尾。

0

不,它是一個函數,它使用可變數量的參數。

0

這不是技術上的多態性。 fcntl採用可變數量的參數&,這是類似於printf函數的原因。

11

...表示您可以將任意數量的參數傳遞給此函數,正如其他評論者已經提到的那樣。由於可選參數沒有輸入,因此編譯器無法檢查類型,並且可以從技術上傳遞任何類型的參數。

那麼這是否意味着你可以使用它來實現某種多態函數? (即,進行基於它的參數類型的一些操作的功能。)

你不能這樣做的原因,是因爲你無法在運行時檢查類型的傳入的參數。預期變量參數列表中的函數讀取已經知道它將要接收的可選參數的類型。

如果函數確實能夠接受任意類型的任意數量的參數(即printf),則參數的類型將通過格式字符串傳入。這意味着調用者必須在每次調用時指定要傳入的類型,從而消除多態函數的好處(調用者也不必知道類型)。

比較:

// Ideal invocation 
x = multiply(number_a, number_b) 
y = multiply(matrix_a, matrix_b) 

// Standard C invocation 
x = multiply_number(number_a, number_b) 
y = multiply_matrix(matrix_a, matrix_b) 

// Simulated "polymorphism" with varargs 
x = multiply(T_NUMBER, number_a, number_b) 
y = multiply(T_MATRIX, matrix_a, matrix_b) 

您必須指定可變參數函數可以做正確的事情之前的類型,所以這次獲得你什麼。

6

C支持多態嗎?不,它不。

但是有幾個庫,比如Python C API,它使用結構和指針實現了多態的粗略變體。請注意,編譯器在大多數情況下不能執行適當的類型檢查。

的tecnhique很簡單:

typedef struct { 
    char * (*to_string)(); 
} Type; 

#define OBJ_HEADER Type *ob_type 

typedef struct { 
    OBJ_HEADER; 
} Object; 

typedef struct { 
    OBJ_HEADER; 
    long ival;   
} Integer; 

typedef struct { 
    OBJ_HEADER; 
    char *name; 
    char *surname; 
} Person; 

整數和人獲得具有適當的函數指針的Type對象(例如像integer_to_string和person_to_string函數)。

現在只需要聲明一個函數接受對象*:

void print(Object *obj) { 
    printf("%s", obj->type->to_string()); 
} 

現在你可以調用這個函數有兩個整數和人:

Integer *i = make_int(10); 
print((Object *) i); 

Person *p = make_person("dfa"); 
print((Object *) p); 

編輯

或者你也可以將i和p聲明爲Object *;當然make_int和make_person將爲整數和人員分配空間,並做相應的轉換:

Object * 
make_integer(long i) { 
    Integer *ob = malloc(sizeof(Integer)); 
    ob->ob_type = &integer_type; 
    ob->ival = i; 
    return (Object *) ob; 
} 

注:我不能編譯這些例子分辯現在,請他們雙檢。

我遇到了下面的函數簽名,我想知道這個(省略號或「...」)是否是某種多態嗎?

是的,它是原始形式的多態性。只有一個功能簽名,您可以通過各種結構。但編譯器無法幫助您檢測類型錯誤。

0

C既不支持函數重載 - 這是一種特設多態性基於編譯時類型 - 也不支持多重分派(即基於運行時類型的重載)。

要在C中模擬函數重載,必須創建多個不同名稱的函數。函數的名稱通常包含類型信息,例如字符的fputc()和字符串的fputs()

通過使用可變參數宏可以實現多個分派。同樣,程序員的工作是提供類型信息,但這次是通過額外的參數來實現的,這個參數將在運行時進行評估 - 與上面給出的方法中的編譯時函數名稱相反。 printf()功能家族可能不是多次調度的最佳例子,但我現在無法想象更好的一個。

存在使用指針而不是可變參數或包裝結構中的值來提供類型註釋的多重分派的其他方法。

4

增加了所說的內容:C通過其他方式支持多態。例如,採用對任意類型的數據進行排序的標準庫qsort函數。

它可以通過無類型(void)指針指向數據。它還需要知道要排序的數據的大小(通過sizeof提供)以及比較對象順序的邏輯。這是通過將函數指針傳遞給qsort函數來完成的。

這是運行時多態性的主要示例。

還有其他方法通過手動管理虛擬功能表來實現面向對象的行爲(尤其是虛擬函數調用)。這可以通過在結構中存儲函數指針並傳遞它們來完成。許多API都這樣做,例如WinAPI甚至使用了面向對象的高級方面,例如基類調用調度(DefWindowProc,模擬調用基類的虛方法)。

1

標準庫的printf的聲明

int printf(const char*, ...); 

試想一下。

0

你可以在C中編寫支持多態行爲的代碼,但...(省略號)不會有太大的幫助。這是針對函數的可變參數。

如果你想要多態行爲,你可以使用聯合和結構來構造一個具有「類型」部分和可變字段的數據結構,具體取決於類型。您還可以在結構中包含函數指針表。噗!你已經發明瞭C++。

1

C支持多態性的粗略形式。即一種類型能夠出現並表現爲另一種類型。它的工作原理與C++下的類似(依靠內存對齊),但必須通過強制轉換來幫助編譯器。例如。可以定義一個結構:

typedef struct { 
    char forename[20]; 
    char surname[20]; 
    } Person; 

然後另一個結構:

typedef struct { 
      char forename[20]; 
      char surname[20]; 
      float salary; 
      char managername[20]; 
      } Employee; 

然後

int main (int argc, int *argv) 
{ 
    Employee Ben; 
    setpersonname((Person *) &Ben); 
} 

void setpersonname(Person *person) 
{ 
    strcpy((*person).Name,"Ben"); 
} 

上面的例子顯示僱員被用作人。

-4

是c不支持多態

的代碼,我們在C++編寫使用虛擬實現多態性 如果先轉換爲通過編譯器的C代碼(一個可以找到細節here)。

衆所周知,C++中的虛擬功能是使用函數指針實現的。

相關問題