Всегда ли так, что sizeof (T) & gt; = alignof (T) для всех типов объектов T?

Для любого типа объекта T это всегда так sizeof(T) по крайней мере такой же большой, как alignof(T)?

Интуитивно это выглядит так, поскольку даже при настройке выравнивания объектов, например:

struct small {
char c;
};

выше того, что было бы обычно, их «размер» также корректируется в сторону увеличения, так что отношения между объектами в массиве имеют смысл, сохраняя выравнивание (по крайней мере, в моем тестирование. Например:

struct alignas(16) small16 {
char c;
};

Имеет как размер, так и выравнивание 16.

39

Решение

По крайней мере, в стандартном C ++ для всего, что вы можете сделать массивом (с длиной> 1), это должно быть правдой. Если у вас есть

Foo arr[2];

а также alignof(Foo) > sizeof(Foo), затем arr[0] а также arr[1] оба не могут быть выровнены.

Как Пример Залмана Стерна показывает, что, по крайней мере, некоторые компиляторы позволят вам объявить тип с выравниванием больше его размера, в результате чего компилятор просто не позволит вам объявить массив этого типа. Это не соответствует стандартам C ++ (он использует атрибуты типа, которые являются расширением GCC), но это означает, что вы можете иметь alignof(T) > sizeof(T) на практике.

Аргумент массива предполагает sizeof(Foo) > 0, что верно для любого типа, поддерживаемого стандартом, но o11c показывает пример, где расширения компилятора нарушают гарантию: некоторые компиляторы допускают массивы 0 длины, с 0 sizeof и положительный alignof,

30

Другие решения

#include <iostream>

typedef double foo __attribute__ ((aligned (64)));
alignas(64) double bar;
double baz __attribute__ ((aligned (64)));

int main(int argc, char *argv[]) {
std::cout << "foo sizeof: " << sizeof(foo) << " alignof: " << alignof(foo) << "\n";
std::cout << "bar sizeof: " << sizeof(bar) << " alignof: " << alignof(decltype(bar)) << "\n";
std::cout << "baz sizeof: " << sizeof(baz) << " alignof: " << alignof(decltype(baz)) << "\n";
}

Компилировать с:

clang++ -std=c++11 alignof_test.cpp -o alignof_test && ./alignof_test

Выход:

foo sizeof: 8 alignof: 64
bar sizeof: 8 alignof: 8
baz sizeof: 8 alignof: 8

Строго говоря, нет, но приведенный выше аргумент re: массивы должен быть сохранен.

12

Согласно стандарт c ++ 11 который представил alignof оператор, sizeof определяется следующим образом (см. 5.3.3 expr.sizeof):

Оператор sizeof возвращает количество байтов в объектном представлении своего операнда

В то время как alignof определение (см. 5.3.6 expr.alignof):

Выражение alignof приводит к требованию выравнивания его типа операнда.

Поскольку определение alignof задает требование, возможно, выдвинутое пользователем, а не спецификацию языка, которым мы можем манипулировать компилятором:

typedef uint32_t __attribute__ ((aligned (64))) aligned_uint32_t;
std::cout << sizeof(aligned_uint32_t) << " -> " << alignof(aligned_uint32_t);
// Output: 4 -> 64

отредактированный

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

aligned_uint32_t arr[2];

Результаты в error: alignment of array elements is greater than element size

Поскольку массивы требуют, чтобы указанный тип соответствовал условию: sizeof(T) >= alignof(T)

8

Многие компиляторы допускают массивы размера 0, Выравнивание остается таким же, как выравнивание элемента подошвы.

(Среди прочего, это полезно для принудительного выравнивания в тех случаях, когда вы не можете использовать битовое поле)

7
По вопросам рекламы [email protected]