2011-12-18 24 views
11

¿Alguien sabe de alguna magia de preprocesador C99 que permite crear una cadena que consta de otra cadena repetida N veces?C macro de preprocesador para devolver una cadena repetida un cierto número de veces

E.g.

STRREP("%s ", 3) 

convierte

"%s %s %s " 

después del procesamiento previo.

La única cosa que podría pensar en mí fue algo como esto

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

que funciona bien, pero es feo como tengo que definir una macro para cada longitud de repetición manual. Quiero usarlo junto con macros variadic y la macro devuelve el número de argumentos de macros mostrados here.

+2

Estoy bastante seguro de que no es posible. Vea otra pregunta aquí que es similar: http://stackoverflow.com/questions/319328/writing-a-while-loop-in-the-c-preprecessor – mattjgalloway

+0

Gracias, @mattjgalloway. Usted parece tener razón. No hay forma de longitud de recursión variable en C99 puro utilizando el preprocesador. Entonces mi idea parece ser la única (¡fea!) Forma. – sonntam

Respuesta

4

Mi sugerencia es utilizar el impulso.

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

¿No es Boost solo para C++? –

+0

@Alex, este código funciona en C. utilizando la plantilla (como para aprovechar C++) no utiliza C. puede utilizar dicho preprocesador. – BLUEPIXY

+0

'BOOST_PP_REPEAT' tiene el límite' BOOST_PP_LIMIT_REPEAT' establecido en '256' (como para 1.48). De todos modos, +1 para la solución. – maverik

0

No está seguro de si se puede hacer con la macro pero puede hacerlo con la función como:

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; 
} 

Ahora se puede usar:

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

UPD: Si quiere evitar malloc/free esta es una variante del primer código:

/* .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; 
} 

Ahora:

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

otoh, esto parece aún más feo que el primero.

+3

Por supuesto, se puede hacer usando funciones, pero me gustaría que la secuencia se conozca en tiempo de compilación. – sonntam

17

Dado que es una macro y N es una constante numérica de todos modos, ¿qué tal esto?

#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

¡Buena idea! Lo guardaré en mis mangas. Gracias. – sonntam

+6

\ * Vomita en toda la pantalla \ * pero es bastante fácil de usar aunque +1 – Thomas

0

Recientemente he descubierto un esquema de recursión con la C-preprocesador mecanismo de inclusión de archivo CPP sobre el preprocesador __INCLUDE_LEVEL__ literal que es tratado de forma automática - así que tal vez este algoritmo sólo funciona para gcc?!?

  • El algoritmo es conceptualmente ilimitado, se puede ampliar con indirección adicional de archivos.
  • El herin presentó código controla un ITERATION_COUNT 0 a 39.202
  • con el comentario/descomentar del ITERATION_SEPARATOR puede generar N elementos, o 1 elemento con N concatenaciones, adecuados para las repeticiones de cuerda.
  • La macro ITERATION_ELEMENT se utiliza como el "elemento de repetición"

Puede compilar el código regularmente, sin ningún define adicionales.La macro invocación dentro del código es idempotente.

Una salida ejemplar:

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

0-1591 Contador

1592 Elementos


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 
Cuestiones relacionadas