Nebenwirkungen in generischen Ausdrücken

Lesezeit: 2 Minuten

Ich mache ein paar Experimente mit dem Neuen _Generic Stichwort und bin auf einen Sonderfall bei Mehrfachauswertungen gestoßen. Siehe Folgendes:

#include <stdio.h>

#define write_char(c) _Generic(c, char: putchar, const char: putchar)(c)

int main(void)
{
    const char *s = "foo";

    write_char(*s++);
    write_char(*s++);
    write_char(*s++);

    putchar('\n');
}

Dies lässt sich gut kompilieren und erzeugt mit GCC das erwartete Ergebnis:

$ gcc -std=c11 -Wall plusplus.c -o plusplus
$ ./plusplus 
foo

Auf der anderen Seite gibt Clang eine große Hupenwarnung aus:

$ clang -std=c11 plusplus.c -o plusplus
plusplus.c:9:18: warning: multiple unsequenced modifications to 's'
      [-Wunsequenced]
    write_char(*s++);
                 ^~
plusplus.c:3:32: note: expanded from macro 'write_char'
#define write_char(c) _Generic(c, char: putchar, const char: putchar)(c)

...

Das Ergebnis ist aber wie erwartet:

$ ./plusplus
foo

Ich überprüfte der Normentwurfdie (auf S. 97 des PDFs) sagt:

Der steuernde Ausdruck einer generischen Auswahl wird nicht ausgewertet.

Dies scheint genau das Problem der Seiteneffekte in Makros zu adressieren (z. B. MIN und MAX).

Kann ich jetzt Clangs Warnung ignorieren, oder irre ich mich?

  • Klingt so, als sollten Sie dem Clang-Entwicklungsteam ein Problem melden, anstatt es zu ignorieren. Möglicherweise sind Sie der Erste, der auf das Problem gestoßen ist. Was passiert, wenn Sie schreiben putchar(*s++)? Erzeugt das auch die Warnung? Vermutlich nicht.

    – Jonathan Leffler

    20. Dezember 2014 um 20:31 Uhr


  • Ich glaube, Sie haben einen Fehler in Clang entdeckt!

    – Hacken

    20. Dezember 2014 um 20:32 Uhr

  • @PascalCuoq, nein, es ist nicht verwandt. Die dort erfolgte Warnung war berechtigt. Hier ist es nicht, es gibt keine unsequenzierten Bewertungen von ++ im angegebenen Code.

    – Jens Gustedt

    20. Dezember 2014 um 20:46 Uhr

  • @doukremt, ich weiß nicht, ob Sie den Fehler bereits gemeldet haben (sehe ihn nicht im Fehler-Tracker), aber nachdem ich Ihr Beispiel ausprobiert und keine Fehler gesehen habe, habe ich den Commit-Verlauf in Clang durchgesehen und gefunden dieses Bekenntnis vom 3. Dezember 2014. Es war also eigentlich ein Fehler, und er ist bereits behoben.

    – xaizek

    7. Februar 2015 um 14:41 Uhr


  • @xaizek Als Referenz für zukünftige Leser können Sie dies als die richtige Antwort auf die Frage posten.

    – Ludin

    5. März 2015 um 16:11 Uhr

Wie ich in den Kommentaren erwähnt habe, haben Sie die Frage etwa zwei Wochen nach der Behebung des Fehlers in Clangs Trunk gepostet. Siehe Überarbeitung rL223266 (3. Dezember 2014). Der Fix ist in Clang 3.6 enthalten.

Kann ich jetzt Clangs Warnung ignorieren, oder irre ich mich?

Wir wissen bereits, dass Sie Recht haben, also ist hier eine Möglichkeit, Pragmas in Clang für die Zukunft zu ignorieren:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunsequenced"

write_char(*s++);

#pragma clang diagnostic pop

Um es nicht bei jeder Verwendung des Makros zu wiederholen, könnten Sie setzen _Pragma in seinem Körper:

#define write_char(c) \
    _Pragma("clang diagnostic push") \
    _Pragma("clang diagnostic ignored \"-Wunsequenced\"") \
    _Generic(c, char: putchar, const char: putchar)(c) \
    _Pragma("clang diagnostic pop")

Das scheint ein Bug gewesen zu sein. Inzwischen ist es gelöst clang 3.6 aufwärts wie gezeigt hier.

1345510cookie-checkNebenwirkungen in generischen Ausdrücken

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy