Hay una publicación antigua que solicita una construcción por la que sizeof
regresaría 0
. Hay algunas respuestas de alta puntuación de usuarios de alta reputación que dicen que, según el estándar, ningún tipo o variable puede tener un tamaño de 0. Y estoy 100% de acuerdo con eso.
Sin embargo, existe esta nueva respuesta que presenta esta solución:
struct ZeroMemory {
int *a[0];
};
Estaba a punto de rechazarlo y comentarlo, pero el tiempo que pasé aquí me enseñó a verificar incluso las cosas de las que estoy 100% seguro. Así que ... para mi sorpresa tanto gcc
y clang
mostrar los mismos resultados: sizeof(ZeroMemory) == 0
. Aún más, el tamaño de una variable es 0
:
ZeroMemory z{};
static_assert(sizeof(z) == 0); // Awkward...
¿Qué ...?
¿Cómo es esto posible?
c++
language-lawyer
sizeof
bolov
fuente
fuente
Respuestas:
Antes de que se estandarizara C, muchos compiladores no habrían tenido dificultades para manejar tipos de tamaño cero siempre que el código nunca intentara restar un puntero a un tipo de tamaño cero de otro. Tales tipos eran útiles y apoyarlos era más fácil y barato que prohibirlos. Sin embargo, otros compiladores decidieron prohibir estos tipos, y algunos códigos de aserción estática pueden haberse basado en el hecho de que chillarían si el código intentara crear una matriz de tamaño cero. Los autores de la Norma se enfrentaron a una elección:
Permitir que los compiladores acepten silenciosamente declaraciones de arreglos de tamaño cero, incluso en los casos en que el propósito de tales declaraciones sea desencadenar un diagnóstico y abortar la compilación, y requiera que todos los compiladores acepten tales declaraciones (aunque no necesariamente en silencio) como produciendo objetos de tamaño cero. .
Permita que los compiladores acepten silenciosamente declaraciones de arreglos de tamaño cero, incluso en los casos en que el propósito de tales declaraciones sea desencadenar un diagnóstico y abortar la compilación, y permitir que los compiladores que encuentren tales declaraciones cancelen la compilación o la continúen a su gusto.
Exija que las implementaciones emitan un diagnóstico si el código declara una matriz de tamaño cero, pero luego permita que las implementaciones cancelen la compilación o la continúen (con la semántica que consideren adecuada) a su gusto.
Los autores del Estándar optaron por el # 3. En consecuencia, las declaraciones de arreglos de tamaño cero son consideradas por la "extensión" del Estándar, a pesar de que tales construcciones fueron ampliamente soportadas antes de que el Estándar las prohibiera.
El estándar C ++ permite la existencia de objetos vacíos, pero en un esfuerzo por permitir que las direcciones de los objetos vacíos se puedan usar como tokens, exige que tengan un tamaño mínimo de 1. Para que un objeto que no tiene miembros tenga un tamaño de Por tanto, 0 violaría la Norma. Sin embargo, si un objeto contiene miembros de tamaño cero, el estándar C ++ no impone requisitos sobre cómo se procesa más allá del hecho de que un programa que contenga dicha declaración debe desencadenar un diagnóstico. Dado que la mayoría del código que usa tales declaraciones espera que los objetos resultantes tengan un tamaño de cero, el comportamiento más útil para los compiladores que reciben dicho código es tratarlos de esa manera.
fuente
struct polygon { int count; POINT sides[0];}; struct { struct polygon poly; POINT pts[3]; } myTriangle = { {3}, {{1,1},{2,2},{2,1} };
. Habría que tener cuidado para asegurarse de que la alineación no causa problemas, pero se pueden tener objetos de duración estática de diferentes tamaños que se pueden procesar indistintamente.Como señaló Jarod42, las matrices de tamaño cero no son C ++ estándar, sino extensiones GCC y Clang.
Agregar
-pedantic
produce esta advertencia:Siempre olvido que
std=c++XX
(en lugar destd=gnu++XX
) no desactiva todas las extensiones.Esto todavía no explica el
sizeof
comportamiento. Pero al menos sabemos que no es estándar ...fuente
sizeof(int*)
aparte (supongo): coliru.stacked-crooked.com/a/e9a3038bf587b65csizeof
para ese tipo tampoco se aplican. Por lo tanto, el comportamiento es una decisión tomada por los desarrolladores del compilador.ZeroMemory* z = (ZeroMemory*)malloc(sizeof(ZeroMemory) + 2 * sizeof(int*)); z.a[1] = new int{1}; /* or whatever, just use indices into a to access dynamic memory after the previous members (in this case: none) */
, por supuesto, ¡esto no es compatible con el estándar! (Esto se puede utilizar para analizar fácilmente mensajes de red de longitud dinámica mediante la conversión a una estructura, por ejemplo).En C ++, una matriz de tamaño cero es ilegal.
ISO / IEC 14882: 2003 8.3.4 / 1:
g ++ requiere que la
-pedantic
bandera dé una advertencia en una matriz de tamaño cero.fuente
Las matrices de longitud cero son una extensión de GCC y Clang. La aplicación
sizeof
a matrices de longitud cero se evalúa como cero .Una clase de C ++ (vacía) no puede tener tamaño
0
, pero tenga en cuenta que la claseZeroMemory
no está vacía. Tiene un miembro con nombre con tamaño0
y la aplicaciónsizeof
devolverá cero.fuente
0
, pero una clase no vacía puede tener tamaño0
... esto no tiene mucho sentido. Pero supongo que este es el tipo de caso de borde conflictivo que se obtiene con las extensiones no estándar.0
. En este caso particular, el miembro de la estructura en sí es de tamaño 0 y esto hace que el tamaño de la estructura sea 0. Sé que es confuso, pero hice todo lo posible para explicarlo.