2010-10-23 18 views
12

Ho un C-program (un modulo Apache, cioè il programma viene eseguito spesso), che va a write() una stringa terminata da 0 su un socket, quindi ho bisogno di conoscerne la lunghezza.Determina la lunghezza della stringa netta al momento della compilazione

La stringa viene #defined come:

#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" 

È lì per favore un modo, meglio che usare strlen(POLICY)+1 alla fase di esecuzione (e quindi il calcolo più e più volte la lunghezza)?

Una direttiva preprocessore che consente di impostare POLICY_LENGTH già al momento della compilazione?

risposta

22

Utilizzare sizeof(). per esempio. sizeof("blah") verrà valutato a 5 in fase di compilazione (5, non 4, poiché il letterale stringa include sempre un carattere di terminazione null implicito).

+0

si potrebbe desiderare di assicuratevi che sia chiaro perché valuta a 5 e non a 4. –

+0

sizeof ("blah") è 5. Ma il problema è che sizeof (blah) dove 'char * blah =" blah "' è 4 perché è una dimensione puntatore nel sistema a 32 bit. È un problema perché non abbiamo bisogno di sizeof ("stringa di cemento"). Abbiamo bisogno di sizeof (given_pointer). Dovrai usare strlen (pointer), ma è sux e la necessità di aggiungere +1 è un problema minore qui. – Val

2

sizeof opere in fase di compilazione

#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 */ 

Se avete bisogno di un simbolo pre-processore con le dimensioni, basta contare i caratteri e scrivere il simbolo te :-)

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

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

+3

@Oli: Immagino che pmg significhi un'espressione valida per l'uso nei condizionali del preprocessore, che 'sizeof' non è .. –

+0

@R: non lo sapevo. Ciò potrebbe potenzialmente essere abbastanza fastidioso ... –

3

Usa 1+strlen(POLICY) e attivare le ottimizzazioni del compilatore. GCC sostituirà strlen (S) con la lunghezza di S in fase di compilazione se il valore di S è noto al momento della compilazione.

0

Ho un problema simile quando uso un compilatore obsoleto (VisualDSP) su una piattaforma embedded che non supporta ancora C++ 11 (e quindi non posso usare constexpr).

Non ho bisogno di valutare la lunghezza della stringa nel precompilatore, ma ho bisogno di ottimizzarlo in un singolo compito.

Solo nel caso qualcuno ha bisogno di questo in futuro, ecco la mia soluzione estremamente hacky che dovrebbe funzionare su compilatori anche schifosi finchè lo fanno corretta ottimizzazione:

#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. 

Questa macro STRLEN vi darà la lunghezza la stringa letterale che fornisci, purché sia ​​lunga meno di 10 caratteri. Nel mio caso questo è sufficiente, ma nel caso degli OP la macro potrebbe dover essere estesa (molto). Dal momento che è altamente ripetitivo, è possibile scrivere facilmente uno script per creare una macro che accetta 1000 caratteri.

PS: Questa è solo una semplice derivazione del problema che stavo veramente cercando di risolvere, che è un valore HASH calcolato staticamente per una stringa, quindi non ho bisogno di usare alcuna stringa nel mio sistema embedded. Nel caso in cui qualcuno è interessato (mi avrebbe risparmiato un giorno di ricerca e risoluzione), questo farà un hash FNV su una piccola stringa letterale che può essere ottimizzato via in un unico compito:

#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")) 
Problemi correlati