2010-10-23 19 views
12

Tengo un C-program (un módulo de Apache, es decir, el programa se ejecuta a menudo), que va a write() una cadena terminada en 0 sobre un socket, así que necesito saber su longitud.Determinar la longitud de cadena #defined en tiempo de compilación

La cadena se #defined como:

#define POLICY "<?xml version=\"1.0\"?>\n" \ 
    "<!DOCTYPE cross-domain-policy SYSTEM\n" \ 
    "\"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd\">\n" \ 
    "<cross-domain-policy>\n" \ 
    "<allow-access-from domain=\"*\" to-ports=\"8080\"/>\n" \ 
    "</cross-domain-policy>\0" 

¿Hay una manera de agradar, mejor que usar strlen(POLICY)+1 en el tiempo de ejecución (y por lo tanto el cálculo de la longitud y otra vez)?

¿Una directiva de preprocesador, que permitiría la configuración de POLICY_LENGTH ya en tiempo de compilación?

Respuesta

22

Use sizeof(). p.ej. sizeof("blah") evaluará a 5 en tiempo de compilación (5, no 4, porque el literal de cadena siempre incluye un carácter de terminación nula implícita).

+0

Es posible que desee asegúrese de que está claro por qué evalúa 5 y no 4. –

+0

sizeof ("bla") es 5. Pero el problema es que sizeof (bla) donde 'char * bla =" blah "' es 4 porque es un tamaño de puntero en el sistema de 32 bits. Es un problema porque no necesitamos sizeof ("cuerda de hormigón"). Necesitamos sizeof (given_pointer). En su lugar, tendrá que usar strlen (puntero) pero es sux y la necesidad de agregar +1 es un problema menor aquí. – Val

2

sizeof obras en tiempo de compilación

#define POLICY "<?xml version=\"1.0\"?>\n" \ 
    "<!DOCTYPE cross-domain-policy SYSTEM\n" \ 
    "\"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd\">\n" \ 
    "<cross-domain-policy>\n" \ 
    "<allow-access-from domain=\"*\" to-ports=\"8080\"/>\n" \ 
    "</cross-domain-policy>\0" 

char pol[sizeof POLICY]; 
strcpy(pol, POLICY); /* safe, with an extra char to boot */ 

Si necesita un símbolo pre-procesador con el tamaño, solo cuentan los personajes y escribir el símbolo mismo :-)

#define POLICY_LENGTH 78 /* just made that number up! */ 
+7

o '#define POLICY_LENGTH (sizeof (POLICY))' ... –

+3

@Oli: supongo que pmg significaba una expresión válida para usar en condicionales de preprocesador, que 'sizeof' no es .. –

+0

@R: No lo sabía. Eso podría ser bastante molesto ... –

3

Uso y 1+strlen(POLICY) activar las optimizaciones del compilador GCC reemplazará strlen (S) con la longitud de S en el tiempo de compilación si el valor de S se conoce en tiempo de compilación.

0

Tengo un problema similar cuando uso un compilador desactualizado (VisualDSP) en una plataforma incrustada que aún no es compatible con C++ 11 (y por lo tanto no puedo usar constexpr).

No necesito evaluar la longitud de la cadena en el precompilador, pero sí necesito optimizarla en una única tarea.

Por si alguien lo necesita en el futuro, aquí está mi solución extremadamente hacky que deben trabajar en compiladores incluso cutres, siempre y cuando lo hacen optimización adecuada:

#define STRLENS(a,i)  !a[i] ? i : // repetitive stuff 
#define STRLENPADDED(a)  (STRLENS(a,0) STRLENS(a,1) STRLENS(a,2) STRLENS(a,3) STRLENS(a,4) STRLENS(a,5) STRLENS(a,6) STRLENS(a,7) STRLENS(a,8) STRLENS(a,9) -1) 
#define STRLEN(a)   STRLENPADDED((a "\0\0\0\0\0\0\0\0\0")) // padding required to prevent 'index out of range' issues. 

Esta macro STRLEN le dará la longitud de el literal de cadena que usted le proporciona, siempre que tenga menos de 10 caracteres. En mi caso, esto es suficiente, pero en el caso de OPs, la macro puede necesitar ser extendida (mucho). Como es muy repetitivo, puede escribir fácilmente un script para crear una macro que acepte 1000 caracteres.

PD: Esto es solo una derivación simple del problema que realmente estaba tratando de solucionar, que es un valor HASH estáticamente calculado para una cadena, así que no necesito usar ninguna cadena en mi sistema integrado. En caso de que a alguien le interesa (que me habría ahorrado un día de búsqueda y resolución), esto va a hacer un hash FNV en una pequeña cadena literal que puede ser optimizado de distancia en una sola misión:

#ifdef _MSC_BUILD 
#define HASH_FNV_OFFSET_BASIS 0x811c9dc5ULL 
#define HASH_TYPE    int 
#else // properly define for your own compiler to get rid of overflow warnings 
#define HASH_FNV_OFFSET_BASIS 0x811c9dc5UL 
#define HASH_TYPE    int 
#endif 
#define HASH_FNV_PRIME   16777619 
#define HASH0(a)    (a[0] ? ((HASH_TYPE)(HASH_FNV_OFFSET_BASIS * HASH_FNV_PRIME)^(HASH_TYPE)a[0]) : HASH_FNV_OFFSET_BASIS) 
#define HASH2(a,i,b)   ((b * (a[i] ? HASH_FNV_PRIME : 1))^(HASH_TYPE)(a[i] ? a[i] : 0)) 
#define HASHPADDED(a)   HASH2(a,9,HASH2(a,8,HASH2(a,7,HASH2(a,6,HASH2(a,5,HASH2(a,4,HASH2(a,3,HASH2(a,2,HASH2(a,1,HASH0(a)))))))))) 
#define HASH(a)     HASHPADDED((a "\0\0\0\0\0\0\0\0\0")) 
Cuestiones relacionadas