c++ memory int alignment

c++ - ¿Hay algún entorno en el que “int” provoque un relleno estructurado?



memory alignment (5)

Específicamente, esto surgió en una discusión:

En cuanto al consumo de memoria, ¿existe la posibilidad de que usar una struct de dos int s tome más memoria que solo dos int s?

O, en términos de lenguaje:

#include <iostream> struct S { int a, b; }; int main() { std::cout << (sizeof(S) > sizeof(int) * 2 ? "bigger" : "the same") << std::endl; }

¿Hay algún entorno razonable 1 (no necesariamente común o actual) en el que este pequeño programa se imprima bigger ?

1 Para aclarar, lo que quise decir aquí es que los sistemas (y los compiladores) se desarrollaron y produjeron en una cantidad significativa, y específicamente no se construyeron ejemplos teóricos solo para demostrar el punto, o prototipos únicos o creaciones de aficionados.


¿Hay algún entorno razonable (no necesariamente común o actual) en el que este pequeño programa se imprima más grande?

No que yo sepa. Sé que no es del todo tranquilizador , pero tengo motivos para creer que no existe tal entorno debido a los requisitos impuestos por el estándar C ++.

En un compilador que cumple con las normas †, se cumple lo siguiente:

  • (1) las matrices no pueden tener ningún relleno entre elementos, debido a la forma en que se puede acceder con los punteros ref ;
  • (2) las estructuras de diseño estándar pueden o no tener relleno después de cada miembro, pero no al principio, porque son compatibles con el diseño con estructuras de diseño estándar "más cortas" -pero iguales- ref ;
  • (3) los elementos de la matriz y los miembros de la estructura están alineados correctamente;

De (1) y (3), se deduce que la alineación de un tipo es menor o igual a su tamaño. Si fuera mayor, una matriz necesitaría agregar relleno para alinear todos sus elementos. Por la misma razón, el tamaño de un tipo es siempre un múltiplo entero de su alineación.

Esto significa que en una estructura como la dada, el segundo miembro siempre estará correctamente alineado, sea cual sea el tamaño y la alineación de los ints, si se coloca justo después del primer miembro, es decir, no se requiere relleno intersticial. Bajo este diseño, el tamaño de la estructura también es un múltiplo de su alineación, por lo que tampoco se requiere un relleno posterior.

No hay un conjunto de valores (tamaño, alineación) que cumpla con los estándares que podamos elegir que haga que esta estructura necesite cualquier forma de relleno.

Cualquier relleno de este tipo necesitaría un propósito diferente. Sin embargo, tal propósito parece difícil de alcanzar. Supongamos que hay un entorno que necesita este relleno por alguna razón. Cualquiera que sea la razón del relleno, es probable que ‡ también se aplique en el caso de matrices, pero a partir de (1) sabemos que no es posible.

Pero supongamos que tal entorno realmente existe y queremos un compilador de C ++ para él. Podría soportar este relleno adicional requerido en los arreglos simplemente haciendo que los ints sean más grandes, es decir, colocando el relleno dentro de los ints. Esto a su vez permitiría una vez más que la estructura sea del mismo tamaño que dos ints y nos deja sin una razón para agregar relleno.

† Un compilador, incluso uno que de otra manera no cumple con el estándar, que recibe cualquiera de estos errores es discutible, así que los ignoraré.

‡ Supongo que en un entorno donde las matrices y las estructuras son primitivas, puede haber alguna distinción subyacente que nos permita tener matrices no rellenadas y estructuras acolchadas, pero nuevamente, no sé nada de eso en uso.


En su ejemplo específico, struct S { int a, b; }; struct S { int a, b; }; , No puedo ver ningún argumento razonable para el relleno. int debería estar ya alineado de forma natural, y si lo está, int * puede y debe ser la representación natural de los punteros, y no es necesario que S * sea ​​diferente. Pero en general:

Algunos sistemas raros tienen punteros con diferentes representaciones, donde, por ejemplo, int * se representa como un entero que representa una dirección de "palabra", y char * es una combinación de una dirección de palabra y un desplazamiento de bytes en esa palabra (donde el desplazamiento de bytes es almacenados en bits altos que no sean necesarios de la dirección de la palabra). La desreferenciación de un char * ocurre en el software al cargar la palabra, y luego se enmascara y cambia para obtener el byte correcto.

En tales implementaciones, puede tener sentido asegurarse de que todos los tipos de estructura tengan una alineación mínima, incluso si no es necesaria para los miembros de la estructura, solo para que el desorden de desplazamiento de bytes no sea necesario para los punteros a esa estructura. Lo que significa que es razonable que dada la struct S { char a, b; }; struct S { char a, b; }; , sizeof(S) > 2 . Específicamente, esperaría sizeof(S) == sizeof(int) .

Nunca he trabajado personalmente con tales implementaciones, así que no sé si realmente producen ese relleno. Pero una implementación que lo haga sería razonable y, al menos, muy cercana a una implementación existente en el mundo real.


No sería totalmente inverosímil que un sistema que solo puede acceder a la memoria en fragmentos de 64 bits tenga la opción de usar un tamaño "int" de 32 bits para la compatibilidad con otros programas que podrían ser superados por uint32_t y así obtener un tipo más grande. . En un sistema de este tipo, una estructura con un número par de valores "int" probablemente no tenga relleno adicional, pero una con un número impar de valores podría hacerlo de manera plausible.

Desde una perspectiva práctica, la única forma en que una estructura con dos valores int necesitaría un relleno sería si la alineación de una estructura fuera más del doble que la de "int". Eso, a su vez, requeriría que la alineación de las estructuras sea más gruesa que 64 bits, o que el tamaño de int sea menor que 32 bits. La última situación no sería inusual en sí misma, pero la combinación de ambos de una manera que haría que la alineación de la estructura sea más del doble de gruesa que la alineación int parecería muy extraña.


Sé que esto no es lo que solicitó, no está en el espíritu de su pregunta (ya que probablemente tenga en mente las clases de diseño estándar), sino que responde estrictamente solo esta parte:

En cuanto al consumo de memoria, ¿existe la posibilidad de que usar una estructura de dos ints requiera más memoria que solo dos ints?

la respuesta es un poco ... si

struct S { int a; int b; virtual ~S() = default; };

con la nota pedante de que C ++ no tiene estructuras, tiene clases. struct es una palabra clave que introduce la declaración / definición de una clase.


Teóricamente, el relleno se utiliza para proporcionar una manera eficiente de acceder al área de memoria. Si agregar el relleno a 2 variables enteras aumentaría la eficiencia que sí, puede tener relleno. Pero prácticamente no he encontrado ninguna estructura con 2 números enteros que tengan bits de relleno.