Подтвердить что ты не робот

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

Для любого типа объекта T всегда всегда имеет место sizeof(T) не менее alignof(T)?

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

struct small {
  char c;
};

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

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

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

4b9b3361

Ответ 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. Выравнивание остается таким же, как выравнивание единственного элемента.

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