C11 Teil des C++ Standards?



  • Hallo,
    ich möchte in meinem C++ Programm die Funktion "aligned_alloc" benutzen. Ich benutze allerdings C++11. Muss ein C++11 konformer Compiler diese Funktion bereitstellen, weil sie im C11 standard steht (siehe HIER)? Oder ist C11 nicht Teil von C++11? Im std namespace steht sie nämlich erst ab C++17 (siehe HIER).

    #include <stdlib.h> // C-header
    int main()
    {
        // funktioniert das garantiert mit C++11?
        int * p = static_cast<int*>(aligned_alloc(32, sizeof(int)));
    }
    
    #include <cstdlib> // C++-header
    int main()
    {
        // erst seit C++17
        int * p = static_cast<int*>(std::aligned_alloc(32, sizeof(int)));
    }
    

  • Mod

    Bis einschließlich C++14 bezieht sich der Standard lediglich auf C99. Siehe den Abschnitt, der sich mit normativen Verweisen befasst: https://timsong-cpp.github.io/cppwp/n4140/intro.refs#2



  • aligned_alloc() ist nicht portabel, cf. https://blogs.msdn.microsoft.com/vcblog/2017/12/19/c17-progress-in-vs-2017-15-5-and-15-6/ (im Post und in den Kommentaren nach "aligned_alloc" suchen).

    Stephan T. Lavavej schrieb:

    The problem is that the implementation has two parts: aligned_alloc() (which we don’t have) and free(), which has been shipping since the dawn of time. As our Universal CRT has to provide binary compatibility, we’re highly restricted in how we can change free()’s behavior.

    Möglicherweise fliegt es auch wieder aus dem Standard:

    Stephan T. Lavavej schrieb:

    When the C++ Standardization Committee (WG21) incorporated the C11 Standard Library by reference, aligned_alloc() was picked up along with everything else. Now that we’ve noticed it, we might want to propose wording to the C++ Standard along the lines of “aligned_alloc() is excluded from what we incorporate by reference”. I consider it to be fairly low on the priority list, though – at the end of the day, it’s just wording, and doesn’t affect the state of the implementation.



  • Sehr interessant. Danke für die Infos! Dann muss ich wohl einen anderen Weg suchen, um portal aligned memory zu allokieren mit C++11 🙂



  • asdfasd schrieb:

    #include <stdlib.h> // C-header
    int main()
    {
        // funktioniert das garantiert mit C++11?
        int * p = static_cast<int*>(aligned_alloc(32, sizeof(int)));
    }
    

    Das ließe sich auch ohne aligned_alloc eventuell halbwegs portabel so oder ähnlich formulieren:

    #include <type_traits>
    #include <memory>
        ...
        auto storage = std::make_unique<std::aligned_storage_t<sizeof(int), 32>>();
        auto p = reinterpret_cast<int*>(storage.get());
    

    Bei automatischen Variablen kann man auch mit alignas() arbeiten.

    Aber:

    Ein Alignment von 32 ist wahrscheinlich auf den meisten Systemen > alignof(std::max_align_t) und damit ein Extended Alignment.
    Die Unterstützung dafür ist leider implementation-defined. Siehe auch https://en.cppreference.com/w/cpp/language/object#Alignment, letzter Absatz.

    Eines meiner derzeit offenen Probleme ist die Unterstützung für Extended Alignment am besten via TMP zur Compile-Zeit zu detektieren, bisher
    habe ich da aber noch keine zufriedenstellende Lösung finden können - wenn jemand eine gute Idee hat: Ich wäre daran auch sehr interessiert 😉

    Zusatz:

    Gerade mal folgendes auspobiert (VS2015):

    auto storage = std::make_unique<std::aligned_storage_t<32, 32>>();
        auto p = reinterpret_cast<int*>(storage.get());
        std::cout << reinterpret_cast<uintptr_t>(p) % 32<< std::endl;
    

    Ausgabe: 16

    Hab ich da was übersehen? 32 ist ja noch nicht soo exotisch, immerhin ist das eine Alignment-Anfordrung für die __m256 -Typen wenn man mit AVX arbeitet.
    Diese aligned_alloc -Alternative scheint also noch wesentlich unbrauchbarer zu sein, als ich erwartet hätte :(. Scheint so als werde ich wohl weiterhin
    meine eigene Wrapper-Funktion verwenden, die unter der Haube je nach System _aligned_malloc , _mm_malloc , posix_memalign und deren jeweilige free -
    Gegenstücke verwendet.

    Weitere Alternative: Eigenes aligned_alloc schreiben, das genügend Speicher mit malloc reserviert, dass sich dieser manuell ausrichten lässt, ohne die
    Grenzen des reservierten Blocks zu überschreiten. Besonders effizient ist das aber nicht, der Speichermanager könnte das sicher besser lösen.

    Ab C++17:
    std::pmr::memory_resource::allocate() erlaubt auch die Angabe eines Alignments, allerdings könnte auch hier wieder das implementation-defined gelten,
    wenn es sich um ein Extended Alignment handelt.



  • Ja, aligned_storage storage muss extended alignment nicht unterstützen:

    It is implementation-defined whether any extended alignment is supported.

    http://en.cppreference.com/w/cpp/types/aligned_storage

    Damit ist man dann auf alignof(max_align_t) beschränkt, was effektiv alignof(long double) ist, was effektiv 8 oder 16 ist.
    http://en.cppreference.com/w/cpp/types/max_align_t

    Wenn ich es richtig verstehe, dann braucht man ab C++17 sich um nichts mehr zu kümmern. z.B.:

    #include <iostream>
    struct alignas(256) A { int i; };
    int main()
    {
        std::cout<<"alignof(A): "<<alignof(A)<<'\n';
        A* p = new A(); // new respektiert extended alignment mit C++17
        if (((uintptr_t)p%256)==0) 
          std::cout<<"succsess"; 
    }
    

    Siehe z.B. hier den Unterschied zwischen C++11 und C++17:
    http://coliru.stacked-crooked.com/a/7c12648703b0f7a1

    Daher dachte ich, ich prüfe einfach, ob __cplusplus==201703L ist. Denn im C++17 Standard steht:

    The following macro names shall be defined by the implementation:
    __cplusplus The integer literal 201703L.

    Allerdings hält sich (mindestens) der Intel 18.0 Compiler nicht dran (der setzt es immer auf 201103L bei mir), sodass diese Methode für mich leider auch wegfällt.



  • Die Sache mit dem Extended Alignment wäre ja nicht so schlimm, wenn der Standard nicht erlauben würde, dieses stillschweigend zu ignorieren,
    oder wenn ein Compiler, der schon alignas() unterstützt, nicht auch mindestens die Alignment-Anforderungen für alle Instruktionen der Ziel-CPU
    korrekt behandelt werden.

    Letzteres scheint aber dennoch bei VS2015 der Fall zu sein, allerdings hätte ich nicht erwartet, dass der Support derart eingeschränkt ist: Wenn
    ich das Programm mit AVX-Codegenerierung baue ( /arch:AVX ), wird zumindest alignas(32) korrekt behandelt - deshalb ist mir das Problem wohl
    bisher auch noch nicht aufgefallen 😉


Anmelden zum Antworten