2011-12-18 12 views
11

Qualcuno sa di una magia del preprocessore C99 che consente di creare una stringa composta da un'altra stringa ripetuta N volte?C macro del preprocessore per la restituzione di una stringa ripetuta un certo numero di volte

E.g.

STRREP("%s ", 3) 

diventa

"%s %s %s " 

dopo la pre-elaborazione.

L'unica cosa che riuscivo a pensare a me è stato qualcosa di simile

#define STRREP(str, N) STRREP_##N(str)  
#define STRREP_0(str) "" 
#define STRREP_1(str) str 
#define STRREP_2(str) str str 
#define STRREP_3(str) str str str 
... 

che funziona bene, ma è brutto come devo definire una macro per ogni lunghezza ripetizione manualmente. Voglio usarlo insieme a macro variadic e la macro restituisce il numero di argomenti macro mostrato here.

+2

Sono abbastanza sicuro che non è possibile. Vedi un'altra domanda qui che è simile - http://stackoverflow.com/questions/319328/writing-a-while-loop-in-the-c-preprocessore – mattjgalloway

+0

Grazie, @mattjgalloway. Sembri avere ragione Non c'è modo di lunghezza di ricorsione variabile in puro C99 usando il preprocessore. Quindi la mia idea sembra essere l'unica (brutta!) Via. – sonntam

risposta

4

Il mio suggerimento è di usare la spinta.

E.g.

#include <stdio.h> 
#include <boost/preprocessor/repetition/repeat.hpp> 

#define Fold(z, n, text) text 

#define STRREP(str, n) BOOST_PP_REPEAT(n, Fold, str) 

int main(){ 
    printf("%s\n", STRREP("%s ", 3));//STRREP("%s ", 3) -> "%s %s %s " 
    return 0; 
} 
+2

Non è Boost solo per C++? –

+0

@alex, questo lavoro di codice in C. utilizzando il modello (come per approfittare di C++) non fa uso di C. può utilizzare tale preprocessore. – BLUEPIXY

+0

'BOOST_PP_REPEAT' ha il limite' BOOST_PP_LIMIT_REPEAT' impostato su '256' (come per 1.48). Ad ogni modo, +1 per soluzione. – maverik

0

Non è sicuro se si può fare con la macro, ma è possibile farlo con la funzione come:

char *strrep(const char *str, int nrep) 
{ 
    if (nrep <= 0 || !str) return NULL; 
    char *buf = malloc(strlen(str) * nrep + 1); 
    if (!buf) return NULL; 
    for (int i = 0; i < nrep; ++i) { 
     strcat(buf, str); 
    } 
    return buf; 
} 

Ora si può utilizzare:

char *r = strrep("%s", 3); 
if (r) { 
    ... 
    free(r); 
} 

UPD: Se vuoi evitare malloc/free questa è una variante del primo codice:

/* .h */ 
#define STRREP_MAX_CHARS 1024 
#define STRREP_INIT static char __strrep_buffer[STRREP_MAX_CHARS] 
#define STRREP(str, nrep) strrep(str, nrep) ? __strrep_buffer : "" 

char *strrep(const char *str, int nrep); 

/* .c */ 
STRREP_INIT; 

char *strrep(const char *str, int nrep) 
{ 
    if (nrep <= 0 || !str) return 0; 
    if (strlen(str) * nrep >= STRREP_MAX_CHARS) return 0; 
    memset(__strrep_buffer, 0, STRREP_MAX_CHARS); 
    for (int i = 0; i < nrep; ++i) { 
     strcat(__strrep_buffer, str); 
    } 
    return __strrep_buffer; 
} 

Ora:

printf("%s\n", STRREP("%s", 3)); 

OTOH, questo sembra ancora più brutto rispetto al primo.

+3

Ovviamente, può essere fatto usando le funzioni, ma mi piacerebbe avere la stringa nota al momento della compilazione. – sonntam

17

Poiché si tratta di una macro e N è una costante numerica comunque, che ne dici di questo?

#include <stdio.h> 

#define REP0(X) 
#define REP1(X) X 
#define REP2(X) REP1(X) X 
#define REP3(X) REP2(X) X 
#define REP4(X) REP3(X) X 
#define REP5(X) REP4(X) X 
#define REP6(X) REP5(X) X 
#define REP7(X) REP6(X) X 
#define REP8(X) REP7(X) X 
#define REP9(X) REP8(X) X 
#define REP10(X) REP9(X) X 

#define REP(HUNDREDS,TENS,ONES,X) \ 
    REP##HUNDREDS(REP10(REP10(X))) \ 
    REP##TENS(REP10(X)) \ 
    REP##ONES(X) 

int main(void) 
{ 
    printf(REP(9,0,7, "*")); // "*" repeated 907 times 
    printf(REP(0,9,2, "#")); // "#" repeated 92 times 
    printf(REP(0,0,1, "@")); // "@" repeated 1 times 
    return 0; 
} 
+0

Bella idea! Continuerò a occuparmene. Grazie. – sonntam

+6

\ * Vomita su tutto lo schermo \ * ma è piuttosto facile da usare anche se +1 – Thomas

0

ho recentemente scoperto uno schema di ricorsione con il C-preprocessore meccanismo di inclusione di file CPP il preprocessore __INCLUDE_LEVEL__ letterale che è considerato automaticamente - quindi forse questo algoritmo funziona solo per gcc?!?

  • L'algoritmo è concettualmente illimitato, può essere esteso con il file indiretto aggiuntivo.
  • Il Herin presentato codice gestisce un ITERATION_COUNT 0-39.202
  • con il commento/rimuovere il commento del ITERATION_SEPARATOR è possibile generare N elementi, o 1 elemento con N concatenazioni, adatto per ripetizioni di stringa.
  • La macro ITERATION_ELEMENT viene utilizzato come "elemento ripetizione"

È possibile compilare il codice regolarmente, senza definisce aggiuntivi.L'invocazione della macro all'interno del codice è idempotente.

Un'uscita esemplificativa:

> gcc -o iterate.c iterate -Wall -s -O3 & & ./iterate.exe

0-1591 contatore

1592 Elements


iterate.c:

#include <stdio.h> 
#include <inttypes.h> 

int main(void) { 

const char * preproc_array[] = { 
#define ITERATION_COUNT   1592    //0-(199*197-1)39202 (maximum counter) 
#define ITERATION_SEPARATOR ,      //this macro, if active, determines wheather there exits N separate elements otherwise, if outcommented, just 1 element with N concatenations 
#define ITERATION_ELEMENT 0-__COUNTER__ Counter\n //the expanded macro as an arbitrary element 
#include "iterate.h" 
}; 

return !printf("%s%"PRIu32" Elements",preproc_array[ 
#ifndef NO_ITERATION_SEPARATOR 
__COUNTER__-1 
#else 
0 
#endif 
], sizeof(preproc_array)/sizeof(const char *)); 

} 

iterate.h:

#define  ITERATION_START 1 //start index of first inclusion 
#define  ITERATION_LIMIT  199 //conforming to CPP preprocessor manual pg. 54 chapter 11.5, a limit of 200 is set arbitrary 
#define  ITERATION(...)  _ITERATION(__VA_ARGS__) 
#define  _ITERATION(...)  #__VA_ARGS__ ITERATION_SEPARATOR 

#ifndef ITERATION_SEPARATOR 
#define ITERATION_SEPARATOR 
#define NO_ITERATION_SEPARATOR 
#endif 

//here begins the recursive algorithm via preprocessor file inclusion, enable the warnings if you want to see how it loops through 

#if __INCLUDE_LEVEL__ <= ITERATION_COUNT/ITERATION_LIMIT 
//~ #warning DIV 
#define ITERATION_END ITERATION_COUNT/ITERATION_LIMIT+3 // + offset 
#include "loop.h" 
#define ITERATION_END ITERATION_LIMIT 
#include "loop.h" 
#include "iterate.h" 
#endif 

#if __INCLUDE_LEVEL__ == ITERATION_START 
//~ #warning MOD 
#define ITERATION_END ITERATION_COUNT%ITERATION_LIMIT+ITERATION_START 
#include "loop.h" 
#if ITERATION_COUNT  % ITERATION_LIMIT 
#define ITERATION_END 3 // + offset 
#include "loop.h" 
#endif 
#endif 

//end of alogrithm 

loop.h:

#if __INCLUDE_LEVEL__ < ITERATION_END 
#include "loop.h" 
ITERATION(ITERATION_ELEMENT) 
#undef ITERATION_END 
#endif 
Problemi correlati