2012-06-21 23 views
6

Quiero que el tamaño de una C struct sea múltiplo de 16 bytes (16B/32B/48B/..). No importa qué tamaño tenga, solo necesita ser múltiplo de 16B. ¿Cómo podría hacer cumplir el compilador para hacer eso? Gracias.C struct size alignment

+4

¿Cuál es el compilador? – Joe

+1

Su título usa la palabra alineación, sin embargo, el cuerpo de su pregunta habla sobre el tamaño de la estructura. ¿Qué es lo que realmente quieres lograr? Y también tengo curiosidad de por qué. –

+0

Y aquí hay un artículo existente que proporciona una solución usando una unión para agregar un tamaño determinado. Sin embargo, esa solución requiere conocer el tamaño de la estructura [Size of Struct] (http://stackoverflow.com/questions/8705665/force-specific-struct-size-in-c), sin embargo, lo que tendría que hacer es usar un cálculo de tamaño para la matriz char como (sizeof (struct it)/16 + 1) * 16 en lugar de una constante numérica. –

Respuesta

5

El tamaño de una estructura C dependerá de los miembros de la estructura, sus tipos y cuántos de ellos hay. Realmente no hay una forma estándar de forzar al compilador a hacer que las estructuras sean múltiplos de algún tamaño. Algunos compiladores proporcionan un pragma que le permitirá establecer el límite de alineación; sin embargo, eso es realmente algo diferente. Y puede haber algunos que tengan ese tipo de configuración o proporcionen tal pragma.

Sin embargo, si insiste en este método uno sería hacer la asignación de memoria de la estructura y forzar la asignación de memoria para redondear hasta el siguiente tamaño de 16 bytes.

Así que si tuviera una estructura como esta.

struct _simpleStruct { 
    int iValueA; 
    int iValueB; 
}; 

Entonces podría hacer algo como lo siguiente.

{ 
    struct _simpleStruct *pStruct = 0; 
    pStruct = malloc ((sizeof(*pStruct)/16 + 1)*16); 
    // use the pStruct for whatever 
    free(pStruct); 
} 

Lo que esto haría es hacer aumentar el tamaño hasta el siguiente tamaño de 16 bytes lo que a ti respecta. Sin embargo, lo que hace el asignador de memoria puede o no ser darle un bloque que es realmente ese tamaño. El bloque de memoria puede ser más grande que tu pedido.

Si va a hacer algo especial con esto, por ejemplo digamos que va a escribir esta estructura en un archivo y desea saber el tamaño del bloque, entonces tendría que hacer el mismo cálculo utilizado en el malloc() en lugar de usar el operador sizeof() para calcular el tamaño de la estructura.

Así que lo siguiente sería escribir su propio operador sizeof() usando una macro como.

#define SIZEOF16(x) ((sizeof(x)/16 + 1) * 16) 

Por lo que yo sé no existe un método fiable para tirar del tamaño de un bloque asignado de un puntero. Normalmente, un puntero tendrá un bloque de asignación de memoria que es utilizado por las funciones de gestión del montón de memoria que contendrán diversos datos de gestión de memoria, como el tamaño de bloque asignado, que en realidad puede ser mayor que la cantidad solicitada de memoria. Sin embargo, el formato de este bloque y su ubicación en relación con la dirección de memoria real proporcionada dependerá del tiempo de ejecución del compilador de C.

+0

Debería [no arrojar el valor de retorno de 'malloc()', en C] (http://stackoverflow.com/a/605858/28169). – unwind

5

Esto depende completamente del compilador y otras herramientas, ya que la alineación no se especifica en profundidad en el estándar ISO C (especifica que la alineación puede realizarse a petición del compilador pero no detalla cómo aplicarla).

Deberá tener en cuenta las funciones específicas de la implementación para su cadena de herramientas del compilador. Puede proporcionar un #pragma pack (o align o alguna otra cosa) que puede agregar a la definición de su estructura.

También puede proporcionar esto como una extensión de idioma. Por ejemplo, gcc le permite añadir atributos de una definición, una de las cuales controla la alineación:

struct mystruct { int val[7]; } __attribute__ ((aligned (16))); 
11

para Microsoft Visual C++:

#pragma pack(push, 16) 

struct _some_struct 
{ 
    ... 
} 

#pragma pack(pop) 

para GCC:

struct _some_struct { ... } __attribute__ ((aligned (16))); 

Ejemplo:

#include <stdio.h> 

struct test_t { 
    int x; 
    int y; 
} __attribute__((aligned(16))); 

int main() 
{ 
    printf("%lu\n", sizeof(struct test_t)); 
    return 0; 
} 

compilado con gcc -o main main.c dará salida a 16. Lo mismo aplica para otros compiladores.

+1

Para gcc __attribute__ alineado, ¿está realmente forzando que el tamaño de la estructura sea múltiplo de 16B? ¿O solo garantiza que la dirección de inicio de la estructura está alineada con 16B? –

+1

Tanto la dirección de inicio como el tamaño de la estructura se alinearán con 16B. Esto se hace para asegurar la alineación correcta de los elementos de la matriz de estructuras. – Romeo

+0

Esto no es verdad. La macro __attribute (aligned (x))) asigna la estructura en un límite x-byte y no tiene nada que ver con el tamaño de la estructura http://gcc.gnu.org/onlinedocs/gcc-3.2.3/gcc /Variable-Attributes.html –

3

tal vez podría hacer una doble estructura, envolviendo su estructura real en un segundo que puede agregar relleno:

struct payload { 
    int a; /*Your actual fields. */ 
    float b; 
    char c; 
    double d; 
}; 

struct payload_padded { 
    struct payload p; 
    char padding[16 * ((sizeof (struct payload) + 15)/16)]; 
}; 

A continuación, se puede trabajar con la estructura acolchada:

struct payload_padded a; 

a.p.d = 43.3; 

Por supuesto , puede utilizar el hecho de que el primer miembro de una estructura comienza a 0 bytes desde donde se inicia la estructura, y trata un puntero a struct payload_padded como si fuera un puntero a struct payload (porque lo es):

float d_plus_2(const struct payload *p) 
{ 
    return p->d + 2; 
} 

/* ... */ 

struct payload_padded b; 
const double dp2 = d_plus_2((struct payload *) &b);