Unter OS X liefert ein einfaches C++-Programm falsche Ergebnisse (die auf die Befehlszeilenoptionen ‘c++03’ vs. ‘c++11’ zurückzuführen sind)

Lesezeit: 4 Minuten

Dieses einfache Programm (wenn es unter Linux kompiliert wurde) gibt KORREKT zwei verschiedene Antworten, je nachdem, ob es mit kompiliert wurde -std=c++0x oder nicht.

Problem: Ich kann dasselbe unter OS X (Mountain Lion, 10.8 SDK) nicht reproduzieren. Was vermisse ich?

#include <iostream>
#include <sstream>

class Thing : public std::ostringstream
{
public:
    Thing() : std::ostringstream() {}
    virtual ~Thing() { std::cerr << str(); }
};

int main(int argc, const char * argv[]) {
    Thing() << "Hello" << std::endl;
    return 0;
}

Um zu sehen, was ich meine, gehen Sie wie folgt vor (zuerst unter Linux, nur um zu sehen, wie es funktionieren sollte):

> g++ main.cpp
> ./a.out
0x401471

> g++ -std=c++0x main.cpp
> ./a.out
Hello

Der erste gibt eine Hex-Adresse aus, der zweite “Hallo”. Dies ist das richtige Verhalten und liegt daran, dass der Betreiber << wird in zwei verschiedene Dinge aufgelöst (in C++03 gibt es keine Rvalue-Referenzen, also los geht’s).

Versuchen Sie nun dasselbe unter OS X:


> xcrun c++ main.cpp
> ./a.out
0x10840dd88

(Dies erzeugt die Hex-Ausgabe korrekt.)


> xcrun c++ -std=c++0x main.cpp
> ./a.out
0x10840dd88

(Ups… immer noch die Hex-Ausgabe… Wir sind im C++11x-Modus, aber vielleicht werden nicht die richtigen Header verwendet?)


HINWEIS: Version des Compilers ist hier:

> xcrun c++ --version
Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn)
Target: x86_64-apple-darwin12.2.0
Thread model: posix

HINWEIS: Dies ist kein C++-Problem an sich, sondern ein OS X-Build-Problem. Für Interessierte wird der Grund, warum es mit C++03 und C++11 zu unterschiedlichen Ergebnissen führt, unten in einer der Antworten hervorgehoben.

  • Ich weiß Ihren Mut zu schätzen, aber es ist schwer genug, normalen Code zu bekommen, um unter OS X richtig zu kompilieren, geschweige denn Code, der sich an die Grenze eines neuen (ish) Standards hält.

    – Charles

    4. Januar ’13 um 1:31

  • Beachten Sie, dass Mountain Lion Clang und nicht GCC verwendet.

    – Porges

    4. Januar ’13 um 1:33

  • #include < stream> kompiliert bei mir nicht. Können Sie die Include-Direktiven korrigieren? — Macht nichts, ich habe mich darum gekümmert.

    – Keith Thompson

    4. Januar ’13 um 1:33


  • Welche Clang-Version verwendest du?

    – N / A

    4. Januar ’13 um 1:40

  • Es wäre schön, wenn Sie die Ausgabe in Ihre Snippets aufnehmen würden, nicht nur die einzugebenden Befehle, um die unterschiedlichen Ergebnisse zu demonstrieren.

    – Barmar

    4. Januar ’13 um 1:45

Unter OS X liefert ein einfaches C Programm falsche Ergebnisse die
Jonathan Wakely

Erstens ist der erwartete Unterschied im Verhalten, weil die operator<<(std::ostream&, const char*) Überladung (es ist eigentlich eine Spezialisierung von Funktionsvorlagen, aber egal für den Moment) hat einen Parameter vom Typ std::ostream& und eine Lvalue-Referenz kann nur an einen Lvalue binden, und in Ihrem Beispiel ist der Stream ein Rvalue, sodass eine Überladung nicht verwendet werden kann. In C++03 bedeutet dies, dass die einzige brauchbare Überladung die std::ostream::operator<<(const void*) Memberfunktion, weil Memberfunktionen kann für Rvalue-Objekte aufgerufen werden, so dass der String als a . geschrieben wird void* Adresse hexadezimal. In C++11 gibt es ein neues operator<<(std::ostream&&, const T&) Funktionsvorlage, die das Schreiben in Rvalue-Streams ermöglicht und an die . weiterleitet operator<<(std::ostream&, const char*) Überladung, sodass die Zeichenfolge statt einer Hex-Adresse ausgegeben wird.

Unter GNU/Linux verwenden Sie vermutlich eine ziemlich aktuelle GCC-Version, die C++11 sowohl im Compiler (g++) als auch in der Standardbibliothek (libstdc++) ziemlich gut unterstützt, also hat sie die operator<<(std::ostream&&, const T&) Überlastung und alles funktioniert einfach.

Unter OS X verwenden Sie wahrscheinlich Clang mit der Standardbibliothek von GCC, libstdc++. Xcode wird standardmäßig mit einer alten Version von GCC (4.2) geliefert und die Standardbibliothek von GCC 4.2 unterstützt C++11 nicht, hat also nicht die operator<< Überladung für Rvalue-Streams. Verwenden von -std=c++0x weist Clang an, C++11-Sprachfeatures (wie rvalue-Referenzen) zu unterstützen, lässt die Bibliothek von GCC 4.2 jedoch nicht auf magische Weise wachsen C++11-Code, der in den Augen des Standardkomitees nicht einmal ein Funkeln war, als GCC 4.2 war freigegeben. Anstatt eine nicht-prähistorische libstdc++ zu liefern, hat Apple stattdessen eine eigene Standardbibliotheksimplementierung für LLVM- und Clang-Projekte geschrieben. Verwenden von -stdlib=libc++ weist clang an, diese libc++-Standardbibliotheksimplementierung anstelle der alten libstdc++ zu verwenden. Da libc++ vor kurzem geschrieben wurde, hat es die operator<< Überladung für Rvalue-Referenzen.

Es scheint ein Problem mit Clang zu sein, das standardmäßig libstdc++ anstelle von libc++ verwendet. Kompilieren wie folgt: clang++ -std=c++0x -stdlib=libc++ test.cpp ergibt die erwartete Leistung.

.

321530cookie-checkUnter OS X liefert ein einfaches C++-Programm falsche Ergebnisse (die auf die Befehlszeilenoptionen ‘c++03’ vs. ‘c++11’ zurückzuführen sind)

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

Privacy policy