2016-07-08 22 views
5

Gibt es einen portablen Weg, der nur auf dem basiert, was der C99-Standard bietet, um die maximal erforderliche Ausrichtung zu finden, die für jeden Datentyp benötigt wird.So ermitteln Sie die maximal erforderliche Ausrichtung in C99

Wie maxalign_t in C++ 11.

Was ich zur Zeit tun, ist das kleinste gemeinsame Vielfache der Berechnung (lcm) der Ausrichtungen von int, long int, long long int, double, void * und size_t als Best-Effort-Weg, um die Ausrichtung zu bestimmen.

Update: Ich brauche dies zur Zeit für einen Wrapper um malloc Implementierung, die Metadaten zu Beginn des Blockes des Speichers speichert und gibt einen Zeiger mit einer höheren Adresse als das, was malloc zurückgekehrt ist.

Antwort

2

Es gibt nicht wirklich eine gute Möglichkeit, das zu tun, weshalb maxalign_t von C11 eingeführt wurde. Allerdings kann ich mir kein gewöhnliches System vorstellen, bei dem ein Typ mit höheren Ausrichtungsanforderungen als intmax_t existiert, so dass Sie das genauso gut verwenden können und die richtige Antwort für 99% der Systeme erhalten, wenn maxalign_t nicht verfügbar ist.

+0

Traurig, das zu hören. Ich werde bewerten, ob es möglich ist, zu C11 zu wechseln, ansonsten benutze intmax_t. – FSMaxB

+0

Um noch paranoider zu sein, können Sie die Ausrichtungsanforderung 'intmax_t' oder' long double' verwenden, je nachdem, welcher Wert größer ist. –

+0

@SteveSummit: Nicht vergessen 'void *'. Ein 128-Bit-Zeigertyp könnte Informationen über die Basisadresse, die Größe und den Versatz kombinieren, wodurch fehlerhafte Zeigermanipulationen viel effektiver gefangen werden können, als dies mit einfachen linearen Zeigern möglich wäre. – supercat

0

Sie können die maximal unterstützte Ausrichtung empirisch ermitteln, indem Sie mehrere Chunks zuweisen und sehen, ob jeder Chunk an einer 16-, 8- oder 4-Byte-Grenze ausgerichtet ist.

bool GetConsistentAlignment(std::size_t alignment) 
{ 
    const unsigned int chunkCount = 16; 
    void * places[ chunkCount ]; 
    memset(places, 0, sizeof(places)); 
    bool consistent = true; 

    for (unsigned int ii = 0; ii < chunkCount; ++ii) 
    { 
     const std::size_t size = 1024 + rand() % 4096; 
     void * chunk = malloc(size); 
     places[ ii ] = chunk; 
    } 

    for (unsigned int ii = 0; ii < chunkCount; ++ii) 
    { 
     void * chunk = places[ ii ]; 
     const std::size_t place = reinterpret_cast< const std::size_t >(chunk); 
     if (place % alignment != 0) 
     { 
      consistent = false; 
     } 
     free(chunk); 
    } 

    return consistent; 
} 

std::size_t GetMaxSupportedAlignment() 
{ 
    static std::size_t maxAlignment = 0; 

    if (maxAlignment == 0) 
    { 
     std::srand(std::time(0)); 
     std::size_t alignment = 64; 
     while (alignment > 1) 
     { 
      const bool isConsistentAlignment = GetConsistentAlignment(alignment); 
      if (isConsistentAlignment) 
      { 
       break; 
      } 
      alignment /= 2; 
     } 
     maxAlignment = alignment; 
    } 

    return maxAlignment; 
} 

GetMaxSupportedAlignment() Aufruf kehrt 8 auf 64-Bit-Betriebssysteme und 4 auf viele 32-Bit-Systemen.

+0

Dies ist nicht wirklich eine praktische Lösung, eher wie eine esoterische.Ihre Vorgehensweise ist probabilistisch, es ist nicht garantiert, immer die zu produzieren gleiches Ergebnis. Außerdem ist es auf Heap-Zuordnungen angewiesen (nicht zu nett) und es ist eigentlich C++, nicht C99. – FSMaxB