2016-07-08 2 views
5

Существует ли переносимый способ, который зависит только от того, что предлагает стандарт C99, для определения максимально необходимого выравнивания, необходимого для любого типа данных.Как определить максимальное требуемое выравнивание в C99

Нравится maxalign_t in C++ 11.

То, что я сейчас делаю вычисляет наименьшее общее кратное (lcm) из створах int, long int, long long int, double, void * и size_t как лучший усилию способ определения выравнивания.

Update: я в настоящее время это нужно для реализации обертки malloc, который хранит метаданные в начале блока памяти и возвращает указатель с большим адресом, чем то, что malloc вернулся.

ответ

2

Существует не очень хороший способ сделать это, поэтому maxalign_t был представлен C11. Хотя, я не могу представить себе обычную систему, где существует тип с более высокими требованиями к выравниванию, чем intmax_t, поэтому вы можете использовать его и получить правильный ответ для 99% систем, если maxalign_t недоступен.

+0

Грустно слышать это. Я буду оценивать, можно ли переключиться на C11, иначе используйте intmax_t. – FSMaxB

+0

Чтобы быть еще более параноидальным, вы можете использовать требование выравнивания 'intmax_t' или' long double', в зависимости от того, что больше. –

+0

@SteveSummit: Не забывайте 'void *'. 128-битный тип указателя мог бы объединять информацию о базовом адресе, размере и смещении, позволяя ошибочным манипуляциям с указателями быть более эффективно, чем это было бы возможно, используя простые линейные указатели. – supercat

0

Вы можете определить максимально поддерживаемое выравнивание эмпирически, выделив несколько кусков и посмотрев, выравнивается ли каждый кусок на границе 16, 8 или 4 байта.

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() будет возвращать 8 на 64-разрядных операционных систем и 4 на многих 32-битных системах.

+0

Это не практическое решение, более похожее на эзотерическое. Ваш подход вероятен, он не гарантирует всегда такой же результат. Также он полагается на распределения кучи (не слишком приятные), и на самом деле это C++, а не C99. – FSMaxB

Смежные вопросы