2016-07-08 53 views
5

Esiste un modo portatile che fa affidamento solo su ciò che lo standard C99 fornisce per individuare l'allineamento massimo richiesto necessario per qualsiasi tipo di dati.Come determinare l'allineamento massimo richiesto in C99

Come maxalign_t in C++ 11.

Quello che sto facendo attualmente sta calcolando il minimo comune multiplo (lcm) degli allineamenti di int, long int, long long int, double, void * e size_t come modo migliore sforzo di determinare l'allineamento.

Aggiornamento: Attualmente bisogno di questo per l'attuazione di un wrapper malloc che memorizza i metadati all'inizio del blocco di memoria e restituisce un puntatore con un indirizzo superiore a quello che malloc è tornato.

risposta

2

Non c'è davvero un buon modo per farlo, ed è per questo che lo maxalign_t è stato introdotto da C11. Tuttavia, non riesco a immaginare un sistema ordinario in cui esiste un tipo con requisiti di allineamento più elevati di intmax_t, quindi è possibile utilizzarlo e ottenere la risposta corretta per il 99% dei sistemi quando maxalign_t non è disponibile.

+0

Triste per sentirlo. Valuterò se è possibile passare a C11 altrimenti usare intmax_t. – FSMaxB

+0

Per essere ancora più paranoico è possibile utilizzare il requisito di allineamento di 'intmax_t' o' long double', a seconda di quale sia maggiore. –

+0

@SteveSummit: non dimenticare 'void *'. Un tipo di puntatore a 128 bit potrebbe combinare le informazioni sull'indirizzo di base, la dimensione e l'offset, consentendo di manipolare erroneamente il puntatore in modo molto più efficace di quanto sarebbe possibile utilizzando semplici puntatori lineari. – supercat

0

È possibile determinare l'allineamento massimo supportato empiricamente allocando più blocchi e verificando se ciascun blocco è allineato su un limite di 16, 8 o 4 byte.

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; 
} 

Calling GetMaxSupportedAlignment() tornerà 8 sui sistemi operativi a 64 bit e 4 su molti sistemi a 32 bit.

+0

Questa non è una soluzione pratica, più simile ad una esoterica. Il tuo approccio è probabilistico, non è garantito che produca sempre stesso risultato. Inoltre si basa su allocazioni di heap (non troppo belle) e in realtà è C++, non C99. – FSMaxB