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))); }
-
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 interessiertZusatz:
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.
Diesealigned_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 jeweiligefree
-
Gegenstücke verwendet.Weitere Alternative: Eigenes
aligned_alloc
schreiben, das genügend Speicher mitmalloc
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_tWenn 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/7c12648703b0f7a1Daher 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 schonalignas()
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