2016-04-02 10 views
-6

Wrong Umsetzung (mit gcc kompiliert):Warum funktioniert diese Implementierung von "strupr" nicht?

#include <stdio.h> 
#include <ctype.h> 

char* strupr(char *str) 
{ 
    while(*str) { 
     *str++ = toupper(*str); 
    } 

    return str; 
} 

int main(void) { 

    char string[] = { "Test String!" }; 
    strupr(string); 
    puts(string); 

    return 0; 
} 

Die Funktion, um die Zeichenfolge in einer unerwarteten Art und Weise ändert, in denen die in Großbuchstaben setzten Zeichen nur von der zweiten char beginnen.

Hinweis str wird zweimal in der Zuweisung verwendet.

+1

Sie geben nichts von einer Funktion mit einem Rückgabewert zurück, und Sie sollten wirklich viel genauer darüber sein, was nicht funktioniert und so weiter. "Nicht arbeiten" ist selten eine nützliche Beschreibung. –

+2

Sie sollten es in einem Debugger durchlaufen. – JJF

+0

Warnung dienen einem Zweck. Achte auf sie! – Olaf

Antwort

3

Diese Implementierung ist ungültig, da sie undefiniertes Verhalten enthält.

Die Erklärung kommt aus dem Abschnitt 6.5, Absatz 2 der Norm:

Zwischen dem vorherigen und nächsten sequence point ein Objekt hat seinen gespeicherten Wert geändert höchstens einmal durch die Auswertung eines Ausdrucks haben. Außerdem darf der vorherige Wert nur gelesen werden, um den zu speichernden Wert zu bestimmen.

Der Standard gibt ein Beispiel für einen Ausdruck, nicht definiertes Verhalten betrachtet wird, um den zweiten Satz zu klären:

a[i++] = i; 

In diesem Ausdruck wird der Wert von i gelesen wird nicht nur den neuen Wert zu bestimmen zu sein gespeichert, sondern auch um den Speicherort eines anderen Werts zu bestimmen.

Dies ist genau das, was in Ihrem Ausdruck geschieht:

*str++ = toupper(*str); 

Der einzige Unterschied ist, dass Ihr Ausdruck Zeiger verwendet, und ruft toupper dazwischen.

Diese Anforderung mag willkürlich erscheinen, hat aber einen Grund. Der C-Standard ermöglicht es dem Compiler, vor oder nach dem Aufruf von toupper sichtbare Effekte von ++ sichtbar zu machen, um Compilerschreibern maximale Flexibilität zu ermöglichen. Ohne eine Beschränkung auf die Verwendung von str in Ausdruck könnte dies zu unterschiedlichem Verhalten auf verschiedenen Plattformen führen, so dass die Standardautoren entschieden haben, es direkt zu verbieten.

+1

Ich dachte, dass ein Funktionsaufruf ein Sequenzpunkt war? Nein? –

+0

..wohl, was auch immer, am besten, um jegliche Verwirrung vollständig zu vermeiden und explizit in zusätzliche Zeilen zu schreiben, um absolut klar zu machen, was passiert. Ich hasse all diesen 'Sequenzpunkt' Mist. IMHO, C wäre besser ohne die pre/post inc/dec Operatoren gewesen :( –

+0

Orite, danke. Immer noch hasse ++/- :) –

Verwandte Themen