2009-01-27 78 views
15

我最近才意識到我在OS X上使用如此多的函數的strdup()函數不是ANSI C的一部分,而是POSIX的一部分。我不想重寫我所有的代碼,所以我想我只是寫我自己的strdup()函數。這並不難,真的,這只是一個malloc()strcpy()。無論如何,我有這個函數,但是如果我編寫這個函數並將其鏈接到我的代碼,並且它已經存在於libc中,我該怎麼辦?我的鏈接器或編譯器是否允許我基本定義自己的函數版本,還是必須給它另一個名稱?如果有一種重用相同名稱的方法,這非常方便,因此如果strcpy()存在於用戶的libc中,他們可以使用它,但是如果它不存在於libc中,他們可以使用我的版本,代碼更改儘可能。strdup()函數

短的版本:

一)當我寫我自己的函數具有相同的名稱作爲一個內置的功能,會發生什麼?

B)我能做些什麼,以避免不好的事情發生在我的平臺上沒有strdup()無需重寫我的代碼,不使用strdup(),這僅僅是一個有點乏味?

回答

20

通常,您只需使用#if來定義在特定編譯器下所需的函數。如果內置庫沒有定義的strdup,有自己定義它(除如果他們在將來定義它,你必須把它取出來。)沒問題

// Only define strdup for platforms that are missing it.. 
#if COMPILER_XYZ || COMPILER_ABC 
char *strdup(const char *) 
{ 
    // .... 
} 
#endif 
+8

如果您覺得雄心勃勃,您甚至可以設置automake和autoconf來配置測試是否需要自己定義strdup所需的宏,而不是列舉您希望支持的所有編譯器和環境。 – 2009-01-27 06:28:24

4

a)當我編寫自己的 函數時,會發生什麼情況,它的內置函數名稱與 相同?

您不能重新定義您正在包含的頭文件中已存在的函數。這將導致編譯錯誤。

B)我能做些什麼,以避免不好的事情 發生在我身上對 沒有的strdup平臺()而無需重寫 我所有的代碼不使用的strdup(),它 只是有點乏味?

我會建議創建自己的包裝函數到的strdup,並更換所有通話使用新的包裝函數。例如:

char *StringDuplicate(const char *s1) 
{ 
#ifdef POSIX 
    return strdup(s1); 
#else 
    /* Insert your own code here */ 
#endif 
} 

改變從的strdup到StringDuplicate所有電話()應該是一個簡單的查找和替換操作,使其成爲一個可行的辦法。特定於平臺的邏輯將保存在一個單獨的位置,而不是散佈在整個代碼庫中。

2

僅供參考:我從未見過沒有定義strdup()的環境。

+1

我過去也喜歡strdup - 直到我告訴那個在irc.freenode.org上## c的人。他們不喜歡它,並認爲如果有兩條簡單線條,保證工作方式 - 爲什麼要依靠不可移植的功能? (strdup在Windows中已棄用,而win ce似乎沒有) – 2009-01-27 05:47:44

+0

msdn表示應該使用_strdup來代替。但我認爲我閱讀這些棄用警告無論如何都是無稽之談:)但今天看到strdup實際上被廣泛使用,這讓我感到驚訝。 – 2009-01-27 05:49:39

6

你可以使用像這樣的宏,這樣你可以使用舊名稱,但鏈接器會看到不同的名稱;

char *my_strdup(const char *s) { 
    char *p = malloc(strlen(s) + 1); 
    if(p) { strcpy(p, s); } 
    return p; 
} 

/* this goes in whatever header defines my_strdup */ 
char *my_strdup(const char *s); 
#define strdup(x) my_strdup(x) 
+0

很好的解決方案,但是你需要在其他一些檢查機制中包裝strdup(x)的#define來確定它是否需要被替換。如果沒有,你可能想使用libc strdup – Matt 2009-08-12 18:54:19

3

您還應該考慮避免創建以str [a-z]開頭的任何標識符(包括函數)。雖然這不是保留,但C標準(ISO/IEC 9899:1999)第7.26節。11(未來的圖書館方向)指出:「以str,mem或wcs開頭的函數名稱和小寫字母可能會添加到標題中的聲明中。」

6

正如Rob Kennedy指出的,如果這個函數存在或不存在,最好的方法是在你的構建腳本里面測試。我知道使用autoconfig這個過程相當簡單,但也可能使用其他跨平臺構建腳本工具。

然後你只需將你的頭文件:


#ifndef HAVE_STRDUP 
# ifdef HAVE__STRDUP 
# define strdup _strdup 
# else 
# define strdup my_strdup 
# endif 
#endif 

的strdup如果在目標平臺上已經存在的libc的版本使用,如果沒有你的自定義功能my_strdup將使用。

編輯:我應該添加一個爲什麼它更好的探索。

首先,編譯器與libc中函數的存在無關。例如採取功能strlcpy。它存在於FreeBSD上,但不在Linux(glibc)上,儘管它們默認都使用gcc。或者如果有人打算用clang編譯你的代碼會發生什麼?

第二個平臺檢查(我不知道是否有一個標準方法)只有在你明確地爲每個平臺添加你想要支持正確的預處理器條件時才能工作。所以假設你已經掌握了在OSX和Win32上編譯你的應用程序,並且你現在想在Linux上編譯它,你必須通過所有的預處理器條件才能看到它們是否適用於Linux。也許你還想支持FreeBSD,OpenBSD等?同樣的工作。通過在構建腳本中進行測試,它可以在沒有任何額外工作的情況下編譯。

-2

如果其他人讀到這樣的話:即使可用,也不要使用平臺的strdup(),並且不要浪費時間/精力用autoconf/automake來使用它。認真地說,這是多麼困難:

char* mystrdup(const char* str) 
{ 
return strcpy(malloc(strlen(str) + 1),str); 
} 

這是否真的保證#ifdefs?編譯器檢查?吻。