c++ - ¿Es siempre el caso que sizeof(T)>=alignof(T) para todos los tipos de objetos T?
c++11 memory-alignment (4)
Para cualquier tipo de objeto T
, ¿siempre se da el caso de que sizeof(T)
sea al menos tan grande como alignof(T)
?
Intuitivamente parece que sí, ya que incluso cuando ajustas la alineación de objetos como:
struct small {
char c;
};
por encima de lo que normalmente sería, su "tamaño" también se ajusta hacia arriba para que la relación entre los objetos en una matriz tenga sentido mientras se mantiene la alineación (al menos en mi testing . Por ejemplo:
struct alignas(16) small16 {
char c;
};
Tiene un tamaño y una alineación de 16.
Al menos en C ++ estándar, para cualquier cosa que pueda hacer una matriz de (con longitud> 1), esto tendrá que ser cierto. Si usted tiene
Foo arr[2];
y alignof(Foo) > sizeof(Foo)
, luego arr[0]
y arr[1]
no se pueden alinear.
Sin embargo, como muestra el ejemplo de Zalman Stern , al menos algunos compiladores le permitirán declarar un tipo con una alineación mayor que su tamaño, con el resultado de que el compilador simplemente no le permitirá declarar una matriz de ese tipo. Esto no es compatible con los estándares C ++ (utiliza atributos de tipo, que son una extensión GCC ), pero significa que puede tener alignof(T) > sizeof(T)
en la práctica.
El argumento de matriz asume sizeof(Foo) > 0
, que es verdadero para cualquier tipo soportado por el estándar, pero o11c muestra un ejemplo donde las extensiones del compilador rompen esa garantía: algunos compiladores permiten matrices de 0 longitudes, con 0 sizeof
y positive alignof
.
De acuerdo con el estándar c ++ 11 que introdujo el operador alignof
, sizeof
se define como el siguiente (ver 5.3.3 expr.sizeof):
El operador sizeof produce el número de bytes en la representación del objeto de su operando
Mientras que la definición de alignof
es (ver 5.3.6 expr.alignof):
Una expresión de alineación de cede los requisitos de alineación de su tipo de operando.
Como la definición de alignof
especifica un requisito, posiblemente realizado por el usuario, en lugar de una especificación del lenguaje, podemos manipular el compilador:
typedef uint32_t __attribute__ ((aligned (64))) aligned_uint32_t;
std::cout << sizeof(aligned_uint32_t) << " -> " << alignof(aligned_uint32_t);
// Output: 4 -> 64
Editado
Como han señalado otros, tales tipos no se pueden usar en matrices, por ejemplo, tratando de compilar lo siguiente:
aligned_uint32_t arr[2];
Resultados en error: alignment of array elements is greater than element size
Ya que las matrices requieren que el tipo especificado cumpla con la condición: sizeof(T) >= alignof(T)
Muchos compiladores permiten matrices de tamaño 0
. La alineación sigue siendo la misma que la alineación del elemento único.
(Entre otras cosas, esto es útil para forzar una alineación particular en los casos en que no se puede usar un campo de bits)
#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";
}
Compilar con:
clang++ -std=c++11 alignof_test.cpp -o alignof_test && ./alignof_test
Salida:
foo sizeof: 8 alignof: 64
bar sizeof: 8 alignof: 8
baz sizeof: 8 alignof: 8
Así que estrictamente hablando, no, pero el argumento anterior re: arrays tiene que ser preservado.