2009-01-27 5 views
15

Ich wurde vor kurzem bewusst, dass die strdup()-Funktion, die ich genossen habe so viel auf OS X ist nicht Teil von ANSI C, sondern Teil von POSIX. Ich möchte nicht meinen gesamten Code neu schreiben, also denke ich, ich werde nur meine eigene strdup() Funktion schreiben. Es ist nicht so schwer, wirklich, es ist nur ein malloc() und ein strcpy(). Wie auch immer, ich habe die Funktion, aber was mache ich, wenn ich diese Funktion schreibe und sie mit meinem Code verbinde, und sie existiert bereits in der libc? Erlaubt mir mein Linker oder Compiler meine eigene Version der Funktion zu definieren oder muss ich einen anderen Namen geben? Es wäre schrecklich praktisch, wenn es einen Weg gäbe, denselben Namen wiederzuverwenden, so dass, wenn strcpy() in der libc des Benutzers vorhanden ist, sie das verwenden könnten, aber wenn es nicht in ihrer libc existierte, könnten sie stattdessen meine Version mit so wenig verwenden Codeänderung wie möglich.strdup() Funktion

Die kurze Version:

a) Was passiert, wenn ich meine eigene Funktion mit dem gleichen Namen wie eine eingebaute Funktion schreiben?

b) Was kann ich tun, um zu verhindern, dass mir auf Plattformen, die strdup() nicht haben, schlechte Dinge passieren, ohne meinen gesamten Code neu zu schreiben, um strdup() nicht zu verwenden, was nur ein bisschen langweilig ist?

Antwort

20

Normalerweise verwenden Sie einfach eine #if, um die Funktion zu definieren, die Sie unter einem bestimmten Compiler haben möchten. Wenn die integrierte Bibliothek nicht strdup definieren, gibt es kein Problem, das es sich bei der Definition (außer wenn sie es tun, definieren, in die Zukunft, werden Sie es nehmen aus.)

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

Wenn Sie ehrgeizig fühlen, könnten Sie sogar auto und autoconf eingerichtet, um die Makro zu konfigurieren notwendig zu testen, ob Sie strdup selbst definieren müssen, sondern alle Compiler aufzuzählen und Umgebungen Sie unterstützen möchten. –

4

a) Was passiert, wenn ich meine eigene Funktion mit dem gleichen Namen wie eine eingebaute Funktion schreibe?

Sie können eine Funktion, die bereits in einer Headerdatei vorhanden ist, nicht neu definieren. Dies führt zu einem Kompilierungsfehler.

b) Was kann ich mir passiert schlechte Dinge zu vermeiden tun auf Plattformen, die ohne zu Umschreiben alle meinen Code nicht verwenden strdup() nicht strdup() haben, die ist nur ein bisschen langweilig?

Ich würde empfehlen, eine eigene Wrapper-Funktion strdup Erstellen und Ersetzen Sie alle Ihre Anrufe über die neue Wrapper-Funktion zu verwenden. Zum Beispiel:

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

Ändern Sie alle Ihre Anrufe von strdup zu StringDuplicate() sollte ein einfaches Suchen und Ersetzen-Operation sein, es ist ein gangbarer Weg zu machen. Die plattformspezifische Logik wird dann an einem einzigen Ort gespeichert und nicht in Ihrer Codebasis verstreut.

2

FYI: Ich persönlich habe nie eine Umgebung gesehen, die strdup() nicht definiert.

+1

ich mochte auch gerne straddup - bis ich das in ## c an irc.freenode.org sagte. sie mögen es nicht, und argumentieren, dass, wenn es einen zweizeiligen einfachen, garantierten Arbeitsweg gibt - warum sollte man sich auf nicht tragbare Funktionen verlassen? (strdup ist in Windows veraltet, und win ce scheint es nicht zu haben) –

+0

msdn sagt man sollte stattdessen _strdup verwenden. aber ich denke, ich lese diese Missbilligung Warnungen sind sowieso Unsinn :) aber heute war es eine Überraschung für mich zu sehen, dass straddup tatsächlich so breit verwendet wird. –

6

Sie könnten einfach ein Makro so verwenden, auf diese Weise können Sie den alten Namen verwenden, aber Linker wird einen anderen Namen sehen;

+0

gute Lösung, aber Sie müssen die # define von strdup (x) innerhalb einiger anderer Prüfmechanismen umhüllen, um festzustellen, ob es ersetzt werden muss. Wenn nicht möchten Sie wahrscheinlich die libc strdup verwenden – Matt

+4

Es gibt nicht viel schaden in * nicht * das überprüfen, außer für mögliche Optimierungen. BTW, oben, könnte schneller sein, wenn Sie strlen cachen und dann memcpy verwenden, da es in vielen Compilern eine intrinsische ist, die als eine einzelne CPU-Anweisung endet. –

3

Sie sollten auch die Erstellung eines beliebigen Bezeichners (einschließlich einer Funktion) vermeiden, der mit str [a-z] beginnt. Während dies nicht reserviert ist, ist der C-Standard (ISO/IEC 9899: 1999) Abschnitt 7.26.11 (zukünftige Bibliotheksanweisungen) states "Funktionsnamen, die mit str, mem oder wcs beginnen, und ein Kleinbuchstabe können zu den Deklarationen in der Kopfzeile hinzugefügt werden." wenn diese Funktionen vorhanden ist oder nicht

6

Als Rob Kennedy stellte die beste Art und Weise in Ihrem Gebäude Skripte zu testen ist. Ich weiß, dass es mit autoconfig ziemlich einfach ist, aber wahrscheinlich mit anderen plattformübergreifenden Bau-Skripten.

Dann legen Sie einfach in Ihrer Header-Datei:


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

Wenn strdup auf der Zielplattform existiert bereits die libc-Version verwendet wird, wenn Ihre Gewohnheit nicht my_strdup Funktion verwendet werden soll.

EDIT: Ich hätte eine Erklärung hinzugefügt, warum es besser ist.

Zuerst ist der Compiler nicht mit dem Vorhandensein einer Funktion in der libc verbunden. Nehmen Sie zum Beispiel die Funktion strlcpy. Es ist unter FreeBSD, aber nicht unter Linux (glibc) vorhanden, obwohl beide gcc standardmäßig verwenden. Oder was passiert, wenn jemand deinen Code mit Klängen kompiliert?

Zweite eine Plattform Prüfung (ich weiß nicht, ob es eine Standardmethode ist) funktioniert nur, wenn Sie ausdrücklich hinzufügen, jeder Platt Sie den richtigen Präprozessor bedingten unterstützen wollen. Angenommen, Sie haben es geschafft, Ihre Anwendung unter OSX und Win32 zu kompilieren, und Sie wollen es jetzt unter Linux kompilieren. Sie müssen alle Präprozessor-Bedingungen durchgehen, um zu sehen, ob sie für Linux funktionieren. Vielleicht möchtest du auch FreeBSD, OpenBSD, etc. unterstützen? Gleiche Arbeit wieder. Mit einem Test in Ihren Gebäudeskripten kann es ohne zusätzliche Arbeit kompilieren.

-2

Wenn noch jemand dies liest: Verwenden Sie nicht die Plattform stradd(), auch wenn sie verfügbar ist, und verschwenden Sie keine Zeit/Mühe mit autoconf/automake, nur um sie zu benutzen. Ernsthaft, wie schwer ist das:

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

Erfordert das wirklich #ifdefs? Compiler überprüft? KUSS.

+16

Was passiert, wenn malloc ausfällt? –