2014-09-12 4 views
6

strlen gibt die Anzahl der Zeichen vor dem abschließenden Nullzeichen zurück. Eine Implementierung von strlen könnte wie folgt aussehen:Strlen auf einer Zeichenfolge mit nicht initialisierten Werten undefiniertem Verhalten?

size_t strlen(const char * str) 
{ 
    const char *s; 
    for (s = str; *s; ++s) {} 
    return(s - str); 
} 

Diese besondere Implementierung dereferenziert s, wo s unbestimmte Werte enthalten. Es ist äquivalent dazu:

int a; 
int* p = &a; 
*p; 

So zum Beispiel, wenn man dies zu tun sind (die strlen verursacht eine falsche Ausgabe zu geben):

char buffer[10]; 
buffer[9] = '\0'; 
strlen(buffer); 

Ist es nicht definiertes Verhalten?

+1

@ user2864740 Sind Sie sicher, dass die Zeichenfolge * muss * einen Wert enthalten? Ist es nicht erlaubt, glücklich auf einem Read-Before-Write zu stürzen? – kay

Antwort

2

Das Aufrufen der Standardfunktion strlen führt zu undefiniertem Verhalten. DR 451 verdeutlicht dies:

Bibliotheksfunktionen nicht definiertes Verhalten zeigen, wenn sie auf unbestimmte Werte verwendet

Für eine tiefergehende Diskussion see this thread.

+0

Mein Kommentar bezieht sich auf die Implementierung einer Strlen-Funktion des Posters. Stimmen Sie zu, dass die Standardbibliothek andere Einschränkungen oder Freiheiten hat. –

+0

buffer [9] ist ziemlich bestimmt ... – Basilevs

+0

@ KC-NH hat meinen Beitrag aktualisiert, um klarzustellen, dass ich über die Standard-'strlen'-Funktion spreche, nicht OPs Pseudo-Implementierung. –

1

Nein, es ist kein undefiniertes Verhalten. Ihre strlen-Funktion stoppt vor dem Ende des Puffers. Wenn Ihre strlen-Funktion auf Puffer [10] verweist, dann ist das ja undefiniert.

Es wird sicherlich ein unerwartetes Verhalten sein, da der größte Teil des Puffers zufällige Daten enthält. "Undefined" ist ein spezielles Wort für Leute, die Sprachstandards schreiben. Es bedeutet, dass alles passieren kann, einschließlich Speicherfehler oder Beenden des Programms. Mit Unerwartetem meine ich, dass es sicher nicht das ist, was der Programmierer wollte. Bei einigen Läufen könnte das Ergebnis von strlen 3 sein oder es könnte 10 sein.

0

Ja, es ist ein undefiniertes Verhalten. Vom Entwurf C11 Standard §J.2 „undefiniert Verhalten“:

Das Verhalten in den folgenden Umständen nicht definiert ist:

...

Der Wert eines Objekts mit automatischer Speicherdauer wird verwendet, während es unbestimmt ist.

+2

Dieser Code verwendet nicht die unbestimmten Werte ('buffer' ist nicht unbestimmt, aber' buffer [0] 'ist). "Strlen" verwendet jedoch die Werte. Außerdem ist dieser Anhang nicht normativ (er soll eine Art Index sein, um verschiedene Fälle von UB zu finden). Der normative Text ist detaillierter und hat einige Ausnahmen, wenn die unbestimmte Verwendung nicht UB ist. –

+1

Das Objekt ist nicht nur "unbestimmt", sondern die Werte sind einfach "unspezifiziert", also kann nichts passieren. –

2

Das Verhalten der angezeigten Variante ist unter diesen Umständen gut definiert.

  • Die Bytes des nicht initialisierten Array haben alle unbestimmten Werte, mit Ausnahme des 10. Element, das Sie 0 gesetzt.
  • Der Zugriff auf einen unbestimmten Wert wäre nur UB, wenn die Adresse des zugrunde liegenden Objekts nie genommen würde oder wenn der Wert eine Trap für den entsprechenden Typ ist.
  • Da dies ein Array ist und der Zugriff auf Array-Elemente durch Zeigerarithmetik erfolgt, ist der erste Fall hier nicht relevant.
  • Alle char Wert kann ohne UB zugegriffen werden, die Klauseln über Trap-Darstellungen im Standard explizit alle Zeichentypen davon ausschließen.
  • Also die Werte, mit denen Sie zu tun haben, sind einfach "unspezifiziert".
  • Das Lesen unspezifizierter Werte kann nach Ansicht einiger Mitglieder des C-Normenausschusses jedes Mal zu unterschiedlichen Ergebnissen führen, was einige einen "whobly" -Zustand oder so nennen. Diese Eigenschaft ist hier nicht relevant, da Ihre Funktion einen solchen Wert höchstens einmal liest.
  • Ihr Zugriff auf die Array-Elemente gibt Ihnen also beliebige, aber gültige char Wert.
  • Sie sind sicher, dass Ihre for Schleife spätestens bei Position 9 stoppt, damit Sie Ihr Array nicht überschreiben.

Also keine "schlechten" Dinge jenseits des Sichtbaren können passieren, wenn Sie Ihre spezifische Version der Funktion verwenden. Aber einen Funktionsaufruf zu haben, der unspezifizierte Ergebnisse hervorbringt, ist sicherlich nichts, was man in echtem Code sehen möchte. So etwas führt hier zu sehr subtilen Fehlern, und Sie sollten es auf jeden Fall vermeiden.

Verwandte Themen