Для любого типа объекта T
это всегда так sizeof(T)
по крайней мере такой же большой, как alignof(T)
?
Интуитивно это выглядит так, поскольку даже при настройке выравнивания объектов, например:
struct small {
char c;
};
выше того, что было бы обычно, их «размер» также корректируется в сторону увеличения, так что отношения между объектами в массиве имеют смысл, сохраняя выравнивание (по крайней мере, в моем тестирование. Например:
struct alignas(16) small16 {
char c;
};
Имеет как размер, так и выравнивание 16.
По крайней мере, в стандартном 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
,
#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: массивы должен быть сохранен.
Согласно стандарт 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)
Многие компиляторы допускают массивы размера 0
, Выравнивание остается таким же, как выравнивание элемента подошвы.
(Среди прочего, это полезно для принудительного выравнивания в тех случаях, когда вы не можете использовать битовое поле)