2010-04-30 11 views
7

Recientemente he estado trabajando en esta plataforma para la cual una base de código heredada emite una gran cantidad de advertencias de "fundición aumenta la alineación con N", donde N es el tamaño del objetivo del molde.Advertencia: el elenco aumenta la alineación requerida

struct Message 
{ 
    int32_t id; 
    int32_t type; 
    int8_t data[16]; 
}; 

int32_t GetMessageInt(const Message& m) 
{ 
    return *reinterpret_cast<int32_t*>(&data[0]); 
} 

Es de esperar que es obvio que una aplicación "real" sería un poco más complejo, pero el punto básico es que tengo los datos procedentes de algún lugar, saben que está alineado (porque necesito el id y tipo a alinear), y sin embargo recibo el mensaje de que el elenco está aumentando la alineación, en el caso de ejemplo, a 4.

Ahora sé que puedo suprimir la advertencia con un argumento para el compilador, y sé que puedo lanzar el bit entre paréntesis para anular * primero, pero realmente no quiero pasar por cada bit de código que necesita este tipo de manipulación (hay mucho porque cargamos mucho dat) un disco que no está en el disco, y que los datos vienen como búfers de carga para que podamos avanzar fácilmente con el puntero), pero ¿alguien puede darme otras ideas sobre este problema? Quiero decir, para mí parece una opción tan importante y común que no querría advertir, y si realmente existe la posibilidad de hacerlo mal, entonces suprimir la advertencia no va a ayudar. Finalmente, ¿no puede el compilador saber como yo sé cómo el objeto en cuestión está realmente alineado en la estructura, por lo que debería ser capaz de no preocuparse por la alineación en ese objeto particular a menos que se golpee un byte o dos?

+0

¿Existe algún tipo de Pragma/Directiva embalado ¿su compilador admite para hacerle saber que la estructura está alineada x byte? –

+0

"esta plataforma", no nos hagas adivinar. –

+0

@ Hans- No puedo compartir detalles específicos de la plataforma. @ Michael: puedo dar la vuelta y comenzar a etiquetar las cosas como alineadas, lo cual empecé a hacer, pero el problema está en todas partes. La pregunta no es tanto "¿cómo lo soluciono?", Sino "por qué al compilador le importa tanto cuando tiene toda la información que necesita". P.ej. no advierte que podría estar desreferenciando a los otros miembros sin alinear ... –

Respuesta

4

Una posible alternativa podría ser:

int32_t GetMessageInt(const Message& m) 
{ 
    int32_t value; 
    memcpy(&value, &(data[0]), sizeof(int32_t)); 
    return value; 
} 

Para la arquitectura x86, la alineación no va a importar mucho, que es más un problema de rendimiento que no es realmente relevante para el código que ha proporcionado. Para otras arquitecturas (por ejemplo, MIPS), los accesos mal alineados provocan excepciones de la CPU.


OK, aquí hay otra alternativa:

struct Message 
{ 
    int32_t id; 
    int32_t type; 
    union 
    { 
     int8_t data[16]; 
     int32_t data_as_int32[16 * sizeof(int8_t)/sizeof(int32_t)]; 
     // Others as required 
    }; 
}; 

int32_t GetMessageInt(const Message& m) 
{ 
    return m.data_as_int32[0]; 
} 

Aquí hay variación de lo anterior que incluye las sugerencias de cpstubing06:

template <size_t N> 
struct Message 
{ 
    int32_t id; 
    int32_t type; 
    union 
    { 
     int8_t data[N]; 
     int32_t data_as_int32[N * sizeof(int8_t)/sizeof(int32_t)]; 
     // Others as required 
    }; 
    static_assert((N * sizeof(int8_t) % sizeof(int32_t)) == 0, 
        "N is not a multiple of sizeof(int32_t)"); 
}; 

int32_t GetMessageInt(const Message<16>& m) 
{ 
    return m.data_as_int32[0]; 
} 


// Runtime size checks 
template <size_t N> 
void CheckSize() 
{ 
    assert(sizeof(Message<N>) == N * sizeof(int8_t) + 2 * sizeof(int32_t)); 
} 

void CheckSizes() 
{ 
    CheckSize<8>(); 
    CheckSize<16>(); 
    // Others as required 
} 
+0

Sí, es una plataforma que activará excepciones de lectura no alineadas a menos que indique que el objeto no está alineado. Ciertamente podría copiar los datos, pero parece excesivo; si leo un archivo del disco que llena la memoria, solo quiero decir "esto está aquí, aquí está, aquí está", y no tiene que estar barajando las cosas sin obtener una ganancia real. –

+1

@ dash-tom-bang: depende del compilador, por supuesto, pero puede obtener esa 'memcpy' por el precio de una lectura no alineada (por lo que el compilador sabe)' int32_t'.Por ejemplo, GCC es bastante bueno en este tipo de cosas, puede optimizar las variables en los registros, incluso si toma una dirección, siempre que no pase la dirección a un código no en línea. –

+0

No creo que la copia haga una gran diferencia si tu compilador tiene un 'memcpy' decente intrínseco. – msandiford

Cuestiones relacionadas