2010-02-28 93 views
50

我只想知道C是否支持加載? 由於我們使用printf等系統函數,其參數不同。 幫我出來C支持重載嗎?

+2

Duplicate:http://stackoverflow.com/questions/479207/function-overloading-in-c – 2010-03-20 10:25:30

+0

請參閱Leushenko 2014年答案使用C11 _泛型類型選擇器在愚蠢http://stackoverflow.com/questions/479207/function -overloading-在-C。 – 2015-04-16 07:52:21

回答

44

不,C不支持任何形式的超載(除非你是內置運營商重載已經是事實,是的超載一種形式)。

printf使用稱爲varargs的功能工作。你讓一個呼叫看起來像它可能過載:

printf("%d", 12); // int overload? 
printf("%s", "hi"); // char* overload? 

其實事實並非如此。只有一個printf函數,但編譯器使用特殊的調用約定來調用它,其中提供的任何參數都按順序放置在堆棧上[*]。 printf(或vprintf)檢查格式字符串並使用它來計算出如何讀取這些參數。這就是爲什麼printf的是不是類型安全:

char *format = "%d"; 
printf(format, "hi"); // undefined behaviour, no diagnostic required. 

[*]標準實際上並不他們在棧中傳遞,或提棧可言,但是這是自然的實現。

+0

我不能爲所有編譯器說話,但是一旦函數返回,與我一起工作的那個調用者就會調整它所推送的參數的堆棧。對於我來說,這對於可變參數函數來說似乎是一個好主意 - 比使函數從堆棧中彈出它們更安全。 – tomlogic 2010-02-28 17:42:14

+1

你說得對,實際上cdecl的調用約定就是這樣的(調用者負責堆棧清理);我刪除了評論以避免混淆其他讀者。真正的問題在於scanf,如果提供的格式字符串不正確,可能會將數據寫入內存中的隨機位置(從堆棧中取出)。 – 2010-02-28 17:47:31

+0

C1X將支持通過類型通用表達式和宏 – Spudd86 2011-07-22 22:30:11

29

C不支持重載。 (顯然,即使它確實如此,它們也不會將它用於printf:對於每種可能的組合類型,您都需要printf!)

printf使用varargs

0

C不支持重載。但是我們可以通過編程我們自己的庫來實現這個功能,而這個庫又可以提供超載支持。

+2

不確定你的意思。提供重載支持的庫看起來像什麼? – sepp2k 2010-02-28 17:12:48

+1

@ sepp2k,一堆函數指針表。 – 2010-02-28 18:10:08

+0

@Carl:聽起來你正在談論一個虛擬表。這是爲了繼承,我不確定這將如何幫助超載。 – sepp2k 2010-02-28 18:13:50

5

不,C不支持重載。如果你想實現類似於C++的重載,你將不得不手動地調整你的函數名稱,使用某種一致的約定。例如:

int myModule_myFunction_add(); 
int myModule_myFunction_add_int(int); 
int myModule_myFunction_add_char_int(char, int); 
int myModule_myFunction_add_pMyStruct_int(MyStruct*, int); 
8

這一切都取決於您如何定義「支持」。

顯然,C語言提供重載運算核心語言中,因爲使用C大多數運營商都重載功能:您可以使用二進制+intlong與指針類型。

然而,在同一時間C不允許你創建你自己的重載函數和C標準庫也有訴諸不同名稱的功能與不同類型(如absfabslabs等使用)。

換句話說,C有一定程度的重載編碼爲核心語言,但標準庫和用戶都不允許自己重載。

-5

沒有c不支持函數重載。 但是如果你使用g ++(一個C++編譯器),你可以把它編譯/工作。

+3

-1,如果你正在編寫C你應該使用C編譯器。 – 2010-02-28 18:51:08

+4

借調。如果您使用C++編譯器來編譯代碼,那麼您正在撰寫的是C++代碼,而不是C代碼。特別是如果您使用C++中不在C中的功能,例如功能重載! – 2010-02-28 21:40:37

+0

認真-2哈哈 – chinmaya 2010-03-01 02:14:20

1

不是直接的,這不是printf的工作方式,但如果類型大小不同,則可以使用宏創建等效的重載函數。 C99標準的tgmath.h中的類型通用數學函數可以用這種方式實現。

1

C標準沒有規定操作符重載;由於許多構建系統無法容納具有相同名稱的多個功能,所以添加它的建議已被拒絕。雖然C++可以通過例如有

void foo(int); 
int foo(char*); 
long foo(char *, char **); 

編譯成一個名爲類似v__foo_i,i__foo_pc和l__foo_pc_ppc [編譯器使用不同的命名規則的功能,雖然C++標準禁止在標識符利用內部雙下劃線的,以使編譯器給東西的名字像上面沒有衝突]。 C標準的作者不希望任何編譯器改變命名約定以允許重載,所以他們不提供它。

編譯器將允許重載靜態和內聯函數而不會產生命名問題;這將在實際中是一樣允許外部聯性功能超載爲有用的,因爲人們可以具有一個頭文件:

void foo_zz1(int); 
int foo_zz2(char*); 
long foo_zz3(char *, char **); 
inline void foo(int x) { foo_zz1(x); } 
inline int foo(char* st) { foo_zz2(st); } 
long foo(char *p1, char **p2) { foo_zz3(p1,p2); } 

我記得在看爲C和C++之間的混合的嵌入式編譯器,其支持上述的作爲一個非標準的延伸,但我對細節並不積極。無論如何,即使一些C編譯器支持重載沒有外部鏈接的函數的重載,C14也不支持它,但我不知道(不幸的是)(不幸)有任何積極的努力將這種特性添加到未來的C標準中。

儘管如此,GCC可以通過使用宏來支持一種重載形式,這種形式的重載不會直接在具有運算符重載的語言中被支持。 GCC包含一個內在的特徵,它將確定一個表達式是否可以作爲編譯時常量進行評估。使用這個內在的,可以寫一個宏,它可以根據參數以不同的方式(包括通過調用函數)來評估表達式。在某些情況下,如果給定編譯時常量參數,公式將作爲編譯時常量進行計算,但在給定可變參數時會產生可怕的混亂情況。作爲一個簡單的例子,假設有人希望位反轉一個32位的值。如果該值是恆定的,一個能做到這一點通過:

#define nyb_swap(x) \ 
    ((((x) & 1)<<3) | (((x) & 2)<<1) | (((x) & 4)>>1) | ((((x) & 8)>>3)) 
#define byte_swap(x) \ 
    ((nyb_swap(x)<<4) | nyb_swap((x) >> 4)) 
#define word_swap(x) \ 
    ((byte_swap(x)<<24) | (byte_swap((x) >> 8)<<16) | \ 
    (byte_swap((x) >> 16)<<8) | (byte_swap((x) >> 24))) 

而像uint32_t x=word_swap(0x12345678);表達只會加載x與0×87654321。另一方面,如果該值不是一個常數,結果將是可怕的:像uint32_t y=word_swap(x);這樣的表達式可能會產生許多指令;使用部分展開的循環調用函數幾乎同樣快,但更緊湊。另一方面,使用循環會阻止將結果視爲編譯時常量。

使用GCC,可以定義一個宏,這將既可以使用固定收益宏,如果在恆定的,或者給一個變量時調用一個函數:

#define wswap(x) \ 
    (__builtin_constant_p((x)) ? word_swap((x)) : word_swap_func((x)) 

這種方法不能做的一切類型基於重載可以做,但它可以做很多事情,重載不能。