Всегда ли так, что sizeof (T) >= alignof (T) для всех типов объектов T?
Для любого типа объекта T
всегда всегда имеет место sizeof(T)
не менее alignof(T)
?
Интуитивно это кажется так, поскольку даже когда вы настраиваете выравнивание объектов типа:
struct small {
char c;
};
выше того, что обычно было бы, их "размер" также корректируется вверх, так что связь между объектами в массиве имеет смысл при сохранении выравнивания (по крайней мере, в . Например:
struct alignas(16) small16 {
char c;
};
Имеет размер и выравнивание 16.
Ответы
Ответ 1
По крайней мере, в стандартном С++ для чего-либо вы можете создать массив (с длиной > 1), это должно быть правдой. Если у вас есть
Foo arr[2];
и alignof(Foo) > sizeof(Foo)
, то arr[0]
и arr[1]
не могут быть выровнены.
Как пример Zalman Stern показывает, хотя, по крайней мере, некоторые компиляторы позволят вам объявить тип с выравниванием больше его размера, в результате чего компилятор просто не позволит вам объявить массив этого типа. Это не соответствует стандартам С++ (он использует атрибуты типа, которые являются расширением GCC), но это означает, что вы можете иметь alignof(T) > sizeof(T)
на практике.
Аргумент массива принимает sizeof(Foo) > 0
, что верно для любого типа, поддерживаемого стандартом, но o11c показывает пример, когда расширения компилятора ломаются, что гарантирует: некоторые компиляторы разрешить массивы длиной 0, с 0 sizeof
и положительными alignof
.
Ответ 2
#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: массивы должны быть сохранены.
Ответ 3
В соответствии с С++ 11 standard, который ввел оператор alignof
, sizeof
определяется следующим образом (см. 5.3.3. 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
Edited
Как указывали другие, такие типы не могут использоваться в массивах, например, пытаются скомпилировать следующее:
aligned_uint32_t arr[2];
Результаты в error: alignment of array elements is greater than element size
Так как массивы требуют, чтобы указанный тип соответствовал условию: sizeof(T) >= alignof(T)
Ответ 4
Многие компиляторы разрешают массивы размером 0
. Выравнивание остается таким же, как выравнивание единственного элемента.
(Помимо всего прочего, это полезно для принудительного выравнивания в случаях, когда вы не можете использовать бит поля)