2011-12-18 10 views
11

Czy ktoś wie o jakiejkolwiek magii preprocesora C99, która pozwala na utworzenie ciągu składającego się z innego ciągu powtórzonego N razy?C Makro preprocesora do zwracania ciągu znaków powtarzanego określoną liczbę razy

E.g.

STRREP("%s ", 3) 

staje

"%s %s %s " 

po wyprzedzającym.

Jedyne co mogę myśleć o sobie było coś takiego

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

który działa dobrze, ale jest brzydki jak muszę zdefiniować makro dla każdej długości powtarzania ręcznie. Chcę użyć go razem z makrami variadic i makro zwracając liczbę argumentów makra pokazanych here.

+2

Jestem całkiem pewien, że to nie jest możliwe. Zobacz inne pytanie tutaj, które jest podobne - http://stackoverflow.com/questions/319328/writing-a-while-loop-in-the-c-preprocessor – mattjgalloway

+0

Dziękuję, @mattjgalloway. Wydajesz się mieć rację. Nie ma możliwości zmiennej długości rekurencji w czystym C99 przy użyciu preprocesora. Tak więc mój pomysł wydaje się być jedynym (brzydkim!) Sposobem. – sonntam

Odpowiedz

4

Moja sugestia to skorzystanie z bonusu.

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

Czy nie zwiększa się tylko w C++? –

+0

@Alex, ten kod działa w C. używając szablonu (jak wykorzystać C++) nie używa C. może używać takiego preprocesora. – BLUEPIXY

+0

'BOOST_PP_REPEAT' ma limit' BOOST_PP_LIMIT_REPEAT' ustawiony na '256' (jak dla 1.48). W każdym razie +1 za rozwiązanie. – maverik

0

Nie wiem, czy można to zrobić za pomocą makra, ale można to zrobić za pomocą funkcji takich jak:

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

Teraz można go używać:

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

UPD: Jeśli chcesz uniknąć malloc/free jest to wariant pierwszego kodu:

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

Teraz:

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

OTOH, wygląda jeszcze brzydiej niż pierwszy.

+3

Oczywiście można to zrobić za pomocą funkcji, ale chciałbym, aby łańcuch był znany podczas kompilacji. – sonntam

17

Ponieważ jest to makro, a N to stała liczbowa, czy to możliwe?

#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

Niezły pomysł! Zatrzymam to w moich rękawach. Dziękuję Ci. – sonntam

+6

\ * Wymiotuje na całym ekranie \ *, ale jest całkiem łatwy w użyciu dzięki +1 – Thomas

0

Niedawno odkryto schemat rekursji z CPP c-preprocesora mechanizm integracji plik nad preprocesora __INCLUDE_LEVEL__ dosłownym, który jest traktowany automatycznie - więc może algorytm ten działa tylko dla gcc?!?

  • Algorytm jest pojęciowo nieskończony, może być rozszerzony o dodatkowy plik pośredni.
  • Herin przedstawiony kod zajmuje się ITERATION_COUNT od 0-39202
  • z komentarzem/Uncomment z ITERATION_SEPARATOR można wygenerowania elementów N lub 1 element z N powiązań,, odpowiednie do powtórek smyczkowych.
  • ITERATION_ELEMENT makro służy jako „element powtarzania”

można skompilować kod regularnie, bez żadnych dodatkowych Definiuje.Makro wywołanie wewnątrz kodu jest idempotentne.

Przykładowy wyjściowa:

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

0-1591 Counter

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 
Powiązane problemy