Obwohl dies nicht empfohlen wird, ist dies sicher, der Gültigkeitsbereich einer statischen Variablen bleibt auch dann aktiv, wenn der Gültigkeitsbereich der Funktion endet. Diese Funktion ist überhaupt nicht sehr Thread-sicher. Eine bessere Funktion würde Sie dazu bringen, a zu bestehen char* buffer und ein maxsize für die GetString() Funktion zu füllen.
Insbesondere gilt diese Funktion nicht als a Reentrant-Funktion denn reentrante Funktionen dürfen unter anderem nicht gibt die Adresse an statische (globale) nicht konstante Daten zurück. Sehen reentrante Funktionen.
Zweites Beispiel: Völlig unsicher
char* const GetString()
{
return "Test";
}
Dies wäre sicher, wenn Sie a const char *. Was du gegeben hast, ist nicht sicher. Der Grund dafür ist, dass Zeichenfolgenliterale in einem Nur-Lese-Speichersegment gespeichert werden können und ihre Änderung zu undefinierten Ergebnissen führen wird.
char* const (const pointer) bedeutet, dass Sie die Adresse, auf die der Zeiger zeigt, nicht ändern können. const char * (Zeiger auf Konstante) bedeutet, dass Sie die Elemente, auf die dieser Zeiger zeigt, nicht ändern können.
Fazit:
Sie sollten entweder Folgendes in Betracht ziehen:
1) Wenn Sie Zugriff auf den Code haben, ändern Sie den GetString einen Parameter von a nehmen char* buffer zu füllen und a maxsize benutzen.
2) Wenn Sie keinen Zugriff auf den Code haben, ihn aber aufrufen müssen, schließen Sie diese Methode in eine andere Funktion ein, die durch einen Mutex geschützt ist. Die neue Methode ist wie in 1 beschrieben.
Nachzügler
static Variablen (in einer Funktion) sind wie bereichsbezogene globale Variablen. Im Allgemeinen sollten sie vermieden werden (wie globale Variablen verursachen sie Wiedereintrittsprobleme), sind aber manchmal nützlich (einige Standardbibliotheksfunktionen verwenden sie). Sie können Zeiger auf globale Variablen zurückgeben, damit Sie Zeiger auf zurückgeben können static auch Variablen.
„Im Allgemeinen sollten sie vermieden werden“ mag zu stark sein, aber es ist sicher, dass Sie sich der Risiken und Einschränkungen bewusst sein sollten. +1 für Klarheit auf warum Es ist in Ordnung.
– dmckee — Ex-Moderator-Kätzchen
17. Januar 2009 um 18:15 Uhr
Ich stimme dmckee zu, die Wiedereintrittsprobleme sind auf das Design der Statik zurückzuführen, die über Funktionsaufrufe hinweg aktiv ist. es ist kein schlechtes Benehmen. aber Sie sollten sich des Risikos in der Tat bewusst sein.
– Johannes Schaub – litb
17. Januar 2009 um 18:18 Uhr
Kommt darauf an, was man unter sicher versteht. Es gibt ein paar Probleme, die ich sofort sehe:
Sie haben a zurückgegeben char * const, wodurch Aufrufer die Zeichenfolge an dieser Stelle ändern können. Möglicher Pufferüberlauf. Oder meinst du a const char *?
Möglicherweise liegt ein Problem mit Wiedereintritt oder Parallelität vor.
Um die zweite zu erklären, bedenken Sie Folgendes:
int a = do_something();
int b = do_something_else();
if (a != 0 && b != 0)
{
fprintf(stderr,
"do_something failed (%s) AND do_something_else failed (%s)\n",
format_error_message(a), format_error_message(b));
}
…was wird gedruckt?
Dasselbe gilt für das Einfädeln.
Jonathan Leffler
Grundsätzlich ja, es ist sicher in dem Sinne, dass der Wert auf unbestimmte Zeit bestehen bleibt, da er statisch ist.
Es ist nicht sicher in dem Sinne, dass Sie einen konstanten Zeiger auf variable Daten zurückgegeben haben, anstatt einen Variablenzeiger auf konstante Daten. Besser ist es, wenn die aufrufenden Funktionen die Daten nicht verändern dürfen:
In dem gezeigten einfachen Fall ist es kaum notwendig, sich um Pufferüberläufe zu kümmern, obwohl meine Version des Codes sich Sorgen macht und eine Nullterminierung sicherstellt. Eine Alternative wäre die Verwendung der Funktion TR24731 strcpy_s stattdessen:
Noch wichtiger ist, dass beide Varianten einen (variablen) Zeiger auf konstante Daten zurückgeben, sodass der Benutzer den String nicht ändern und (wahrscheinlich) außerhalb des Bereichs des Arrays trampeln sollte. (Wie @trager in den Kommentaren betont, gibt die Rückgabe von a const char * ist keine Garantie dafür, dass der Benutzer nicht versucht, die zurückgegebenen Daten zu ändern. Sie müssen jedoch den zurückgegebenen Zeiger so umwandeln, dass er nicht konstant ist, und dann die Daten ändern. dies ruft undefiniertes Verhalten hervor und an diesem Punkt ist alles möglich.)
Ein Vorteil der wörtlichen Rückgabe besteht darin, dass die No-Write-Zusage normalerweise vom Compiler und Betriebssystem erzwungen werden kann. Die Zeichenfolge wird in das Textsegment (Codesegment) des Programms eingefügt, und das Betriebssystem generiert einen Fehler (Segmentierungsverletzung unter Unix), wenn der Benutzer versucht, die Daten zu ändern, auf die der Rückgabewert verweist.
[At least one of the other answers notes that the code is not re-entrant; that is correct. The version returning the literal is re-entrant. If re-entrancy is important, the interface needs to be fixed so that the caller provides the space where the data is stored.]
Johannes Schaub – litb
Ja, es ist absolut sicher. Die Lebensdauer der lokalen Statik ist die der gesamten Programmausführung in C. Sie können also einen Zeiger darauf zurückgeben, da das Array auch nach der Rückkehr der Funktion am Leben ist und der zurückgegebene Zeiger gültig dereferenziert werden kann.
Nuklear
Dies ist sehr nützlich, da Sie die Funktion direkt als printf-Parameter verwenden können. Aber wie bereits erwähnt, verursachen mehrere Aufrufe der Funktion innerhalb eines einzigen Aufrufs ein Problem, da die Funktion denselben Speicher verwendet und ein zweimaliger Aufruf die zurückgegebene Zeichenfolge überschreibt. Aber ich habe dieses Stück Code getestet und es scheint zu funktionieren – Sie können eine Funktion sicher aufrufen, bei der Givemestring höchstens MAX_CALLS-mal verwendet wird und sich korrekt verhält.
Das einzige Problem ist die Thread-Sicherheit, aber dies kann mit lokalen Thread-Variablen (dem __thread-Schlüsselwort von gcc) gelöst werden.
Jonathan Leffler
Ja, dies wird häufig verwendet, um den Textteil einer Suche zurückzugeben, dh um eine Fehlernummer in eine benutzerfreundliche Zeichenfolge zu übersetzen.
Es ist ratsam, dies in Fällen zu tun, in denen Sie:
fprintf(stderr, "Error was %s\n", my_string_to_error(error_code));
Wenn my_string_to_error() einen zugewiesenen String zurückgibt, würde Ihr Programm angesichts der oben genannten (sehr) häufigen Verwendung einer solchen Funktion lecken.