2012-07-17 19 views
15

El uso de memoria es bastante crítico en mi aplicación. Por lo tanto, tengo afirmaciones específicas que comprueban el tamaño de la memoria en tiempo de compilación y dan un static_assert si el tamaño es diferente de lo que consideramos correcto antes.Cómo combinar static_assert con sizeof y stringify?

he definido una macro como esta:

#define CHECKMEM(mytype, size) static_assert((sizeof(objectType) == size)), "Size incorrect for " #mytype "!"); 

Esta macro hace que sea muy fácil de escribir esto:

CHECKMEM(Book,144); 
CHECKMEM(Library,80); 

El problema es que cuando este static_assert se apaga, que podría ser bastante es difícil averiguar cuál debe ser el nuevo tamaño (por ejemplo, utilizando la opción del compilador oculto "/ d1 reportAllClassLayout"). Sería mucho más útil si pudiera incluir el tamaño real, entonces en lugar de:

¡Tamaño incorrecto de libro!

Esto mostraría

tamaño incorrecto para libro! (Esperado 144, el tamaño es 152)

intenté escribir algo como esto:

#define CHECKMEM(mytype, size) static_assert((sizeof(objectType) == size)), "Size incorrect for " #mytype "! (expected" #size ", size is " #sizeof(mytype) ")"); 

Pero no se puede utilizar el operador (#) stringize en una llamada de función.

También probé añadiendo el truco de doble stringize, así:

#define STR1(x) #x 
#define STR2(x) STR1(x) 
#define CHECKMEM(mytype, size) static_assert((sizeof(objectType) == size)), "Size incorrect for " #mytype "! (expected" #size ", size is " STR2(sizeof(mytype)) ")"); 

Pero en lugar de imprimir size is 152 Imprime size is sizeof(Book).

¿Hay alguna forma de codificar el resultado de sizeof en un static_assert?

+2

Tenga en cuenta que 'sizeof' es * no * una llamada de función –

+2

El problema es que el segundo argumento para' static_assert' debe ser un literal de cadena y no puede compilarlo en el preprocesador, ya que no puede usar sizeof allí . – pmr

Respuesta

17

que haría uso de despachar en una plantilla de función que hacer la revisión:

#include <cstddef> 

template <typename ToCheck, std::size_t ExpectedSize, std::size_t RealSize = sizeof(ToCheck)> 
void check_size() { 
    static_assert(ExpectedSize == RealSize, "Size is off!"); 
} 

struct foo 
{ 
    char bla[16]; 
}; 

int main() 
{ 
    check_size<foo, 8>(); 
    return 0; 
} 

Resultados: en

información
In instantiation of ‘void check_size() [with ToCheck = foo; long unsigned int ExpectedSize = 8ul; long unsigned int RealSize = 16ul]’: 
bla.cpp:15:22: required from here 
bla.cpp:5:1: error: static assertion failed: Size is off! 

La depuración se encuentra en los parámetros de la plantilla de la parte posterior-trace.

Si esto es realmente mejor, tendrá que decidir y también depende del compilador. También le permite ocultar el tamaño esperado con un mapa de plantilla, para resumir hasta un tamaño máximo y otras cosas sofisticadas.

3

Dependiendo de su compilador, las plantillas pueden ser capaces de ayudar a:

template<int s, int t> struct check_size { 
    static_assert(s == t, "wrong size"); 
}; 
check_size<2+2, 5> doubleplusungood; 

salidas gcc:

prog.cpp: In instantiation of 'check_size<4, 5>': 
prog.cpp:5:20: instantiated from here 
prog.cpp:2:3: error: static assertion failed: "wrong size" 
1

Como has descubierto, el problema es que aquí (ver también este very similar question):

#define CHECKMEM(mytype, size) #sizeof(mytype) 

No se puede hacer, porque la cadena es hecha por la preparación rocessor, y sizeof se evalúa durante la compilación.