Possiamo avere ricorsiva macro?

Voglio sapere se si può avere ricorsiva macro in C/C++? Se sì, si prega di fornire un esempio del campione.

Seconda cosa: perché non sono in grado di eseguire il seguente codice? Qual è l’errore che sto facendo? E ‘ a causa di ricorsive macro?

# define pr(n) ((n==1)? 1 : pr(n-1))
void main ()
{
    int a=5;
    cout<<"result: "<< pr(5) <<endl;
    getch();
}
  • C macro, testo macro. Se le macro sono ricorsiva, si sarebbe SEMPRE costruire un infinito espressione, perché le macro possono fare letteralmente niente altro che ‘sostituire questo con che’
  • In realtà le macro possono fare molto di più. Parametri di quotazione, di concatenazione di Testo e iterativo, in sostituzione di seguito le macro definite. Ma non ricorsione.
  • Non so PERCHÉ vuoi fare questo. se avete intenzione di fare ricorsiva di calcolo in fase di compilazione, si potrebbe essere interessati a modelli variadic (una nuova funzionalità del nuovo standard C++).
  • no, ma i modelli, invece, sono Turing-completo.stackoverflow.com/questions/189172/c-templates-turing-complete

 

5 Replies
  1. 20

    Il compilatore probabilmente è un’opzione che consente solo di pre-processo, in realtà non compilare. Questo è utile se si sta cercando di trovare un problema in una macro. Per esempio utilizzando g++ -E:

    > g++ -E recursiveMacro.c
    
    # 1 "recursiveMacro.c"
    # 1 "<built-in>"
    # 1 "<command line>"
    # 1 "recursiveMacro.c"
    
    void main ()
    {
        int a=5;
        cout<<"result: "<< ((5==1)? 1 : pr(5 -1)) <<endl;
        getch();
    }

    Come si può vedere, non è ricorsivo. pr(x) è solo sostituito una volta durante la fase di pre-elaborazione. La cosa importante da ricordare è che tutti i pre-processore non è ciecamente sostituire una stringa di testo con un altro, in realtà, non si valutano le espressioni come (x == 1).

    Il motivo per cui il codice non viene compilato è che pr(5 -1) non è stato sostituito dal pre-processore, in modo che si finisce in origine come una chiamata a una funzione non definita.

    • il motivo per cui pr(5-1) viene trattata come una funzione non definita chiama???? Ho definito una macro così dovrebbe espandere ulteriormente per: ((5-1==1)? 1 : pr(5-1-1)) ….
    • veredesmarald — possiamo avere ricorsiva macro, prima di tutto???
    • No, non è possibile avere ricorsiva macro. Se effettivamente ha fatto tenere la sostituzione pr(x) con pr(x-1) sarebbe solo un ciclo all’infinito pr(x-1), pr(x-1-1), pr(x-1-1-1), ecc…
    • veredesmarald-Quindi vuoi dire “non può avere ricorsiva macro?”. Inoltre…c’è qualche soluzione alternativa per ottenere che?
    • No. Non è possibile. Quello che tu proponi non ha senso nel contesto di un pre-processore. Come mai colpito una base caso per la ricorsione quando tutto quello che stai facendo è la sostituzione di una stringa con se stesso + altre cose più e più volte?
    • veredesmarald — Grazie 🙂 capito.
    • Questo solo risposto la seconda qst, non il primo.
    • quindi, l’errore sarà “call to undefined function” o loop infinito?

  2. 107

    Macro non direttamente espandere in modo ricorsivo, ma ci sono soluzioni alternative. Quando il preprocessore scansioni e si espande pr(5):

    pr(5)
    ^

    crea un disattivazione di contesto, in modo che quando si vede pr di nuovo:

    ((5==1)? 1 : pr(5-1))
                 ^

    diventa dipinto di blu, e non è più possibile espandere, non importa quello che cerchiamo. Ma possiamo evitare che la nostra macro di diventare dipinto di blu utilizzando differite espressioni e alcuni riferimenti indiretti:

    # define EMPTY(...)
    # define DEFER(...) __VA_ARGS__ EMPTY()
    # define OBSTRUCT(...) __VA_ARGS__ DEFER(EMPTY)()
    # define EXPAND(...) __VA_ARGS__
    
    # define pr_id() pr
    # define pr(n) ((n==1)? 1 : DEFER(pr_id)()(n-1))

    Così ora si espanderà come questo:

    pr(5) //Expands to ((5==1)? 1 : pr_id ()(5 -1))

    Che è perfetto, perché pr non è mai stato dipinto di blu. Abbiamo solo bisogno di applicare un’altra scansione per farlo crescere ulteriormente:

    EXPAND(pr(5)) //Expands to ((5==1)? 1 : ((5 -1==1)? 1 : pr_id ()(5 -1 -1)))

    Possiamo applicare due scansioni di farlo crescere ulteriormente:

    EXPAND(EXPAND(pr(5))) //Expands to ((5==1)? 1 : ((5 -1==1)? 1 : ((5 -1 -1==1)? 1 : pr_id ()(5 -1 -1 -1))))

    Tuttavia, poiché non vi è alcuna condizione di terminazione, non si può mai applicare abbastanza scansioni. Io non sono sicuro di quello che si vuole realizzare, ma se siete curiosi su come creare ricorsiva macro, qui è un esempio di come creare una ricorsiva ripetere macro.

    Primo di una macro per applicare un sacco di scansioni:

    #define EVAL(...)  EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
    #define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
    #define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
    #define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
    #define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__)))
    #define EVAL5(...) __VA_ARGS__

    Accanto, un concat macro che è utile per il pattern matching:

    #define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
    #define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__

    Di incremento e decremento contatori:

    #define INC(x) PRIMITIVE_CAT(INC_, x)
    #define INC_0 1
    #define INC_1 2
    #define INC_2 3
    #define INC_3 4
    #define INC_4 5
    #define INC_5 6
    #define INC_6 7
    #define INC_7 8
    #define INC_8 9
    #define INC_9 9
    
    #define DEC(x) PRIMITIVE_CAT(DEC_, x)
    #define DEC_0 0
    #define DEC_1 0
    #define DEC_2 1
    #define DEC_3 2
    #define DEC_4 3
    #define DEC_5 4
    #define DEC_6 5
    #define DEC_7 6
    #define DEC_8 7
    #define DEC_9 8

    Alcune macro utili per le istruzioni condizionali:

    #define CHECK_N(x, n, ...) n
    #define CHECK(...) CHECK_N(__VA_ARGS__, 0,)
    
    #define NOT(x) CHECK(PRIMITIVE_CAT(NOT_, x))
    #define NOT_0 ~, 1,
    
    #define COMPL(b) PRIMITIVE_CAT(COMPL_, b)
    #define COMPL_0 1
    #define COMPL_1 0
    
    #define BOOL(x) COMPL(NOT(x))
    
    #define IIF(c) PRIMITIVE_CAT(IIF_, c)
    #define IIF_0(t, ...) __VA_ARGS__
    #define IIF_1(t, ...) t
    
    #define IF(c) IIF(BOOL(c))
    
    #define EAT(...)
    #define EXPAND(...) __VA_ARGS__
    #define WHEN(c) IF(c)(EXPAND, EAT)

    Mettere tutto insieme possiamo creare una ripetizione macro:

    #define REPEAT(count, macro, ...) \
        WHEN(count) \
        ( \
            OBSTRUCT(REPEAT_INDIRECT) () \
            ( \
                DEC(count), macro, __VA_ARGS__ \
            ) \
            OBSTRUCT(macro) \
            ( \
                DEC(count), __VA_ARGS__ \
            ) \
        )
    #define REPEAT_INDIRECT() REPEAT
    
    //An example of using this macro
    #define M(i, _) i
    EVAL(REPEAT(8, M, ~)) //0 1 2 3 4 5 6 7

    Così, sì, con alcuni accorgimenti si può avere ricorsiva macro in C/C++.

    • Provando questo in gcc 4.8.3 con -std=c99 dà errore per la linea OBSTRUCT(REPEAT_INDIRECT) (): error: 'REPEAT_INDIRECT' undeclared here (not in a function) . Spostando la definizione di REPEAT_INDIRECT fino a prima di RIPETERE non riuscite.
    • Qual è l’output del preprocesor?
    • La OSTRUIRE la macro non viene espanso qui perché non è qui definito. @Paolo la definisce in il suo post originale.
  3. 18

    Non siete dovrebbe avere ricorsiva macro in C o C++.

    Lingua dal C++ standard, sezione 16.3.4 paragrafo 2:

    Se il nome della macro da sostituire è trovato durante la scansione di un elenco di sostituzione (non compreso il resto del file di origine pre-elaborazione dei token), non viene sostituito. Inoltre, se nidificati sostituzioni incontro il nome della macro di essere sostituito, non viene sostituito. Questi nonreplaced nome macro pre-elaborazione dei token non sono più disponibili per l’ulteriore sostituzione, anche se sono di seguito (re)ha esaminato in contesti in cui tale nome macro pre-elaborazione token, al contrario, sarebbe stato sostituito.

    C’è qualche scappatoia in questa lingua. Con più macro che richiamano l’un l’altro, c’è una zona grigia, in cui formulazione che non riesce a dire ciò che deve essere fatto. È attivo un problema contro il C++ standard per quanto riguarda questa lingua avvocato problema; vedere http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#268 .

    Ignorando che la lingua avvocato problema, tutti i fornitori del compilatore capisce l’intento:

    Ricorsiva macro non sono ammessi in C o in C++.

  4. 11

    Molto probabilmente non sono in grado di eseguire, perché non è possibile compilarlo. Anche se è compilato correttamente, sarebbe sempre tornare 1. Volevi dire (n==1)? 1 : n * pr(n-1).

    Macro non può essere ricorsiva. Secondo capitolo 16.3.4.2 (grazie Loki Astari), se l’attuale macro è trovato nell’elenco di sostituzione, si è lasciato così com’è, così il vostro pr nella definizione non sarà cambiato:

    Se il nome della macro da sostituire è trovato durante la scansione di
    l’elenco di sostituzione (non compreso il resto del file di origine pre-
    elaborazione token), non viene sostituito. Inoltre, se nidificati
    sostituzioni incontro il nome della macro di essere sostituito, non è
    sostituito. Questi nonreplaced nome macro pre-elaborazione dei token sono
    più a vostra disposizione per una sostituzione, anche se sono più avanti
    (re)ha esaminato in contesti in cui tale nome macro pre-elaborazione token
    al contrario, sarebbe stato sostituito.

    Chiamata:

    cout<<"result: "<< pr(5) <<endl;

    è stato convertito dal preprocessore in:

    cout<<"result: "<< (5==1)? 1 : pr(5-1) <<endl;

    Durante questo, la definizione di pr macro è ‘perso’, e il compilatore indica un errore come “‘pr’ non è stato dichiarato in questo ambito (fatto)” perché non c’è alcuna funzione denominata pr.

    Utilizzo di macro non è consigliato, in C++. Perché non basta scrivere una funzione?

    In questo caso si potrebbe anche scrivere una funzione di modello, quindi sarà risolto a tempo di compilazione, e si comporterà come un valore costante:

    template <int n>
    int pr() {  pr<n-1>(); }
    
    template <>
    int pr<1>() { return 1; }
    • La mia intenzione è da sapere su ricorsiva macro. Io non sono alla ricerca di un modo migliore di stampa di un certo valore…. Io non sono sicuro se si può avere un ricorsiva macro o meno.
    • Il tuo ragionamento è viziato. La macro algoritmo di sostituzione viene ripetuto se la macro contiene altre macro (fino a quando non la sostituzione è fatto). Quindi potenzialmente si potrebbe fare ricorsiva macro. MA la lingua spec proibisce esplicitamente dicendo che una volta che una macro viene sostituita rimossa dal potenziale di lista per la sostituzione successiva (all’interno della stessa linea).
    • Grazie, risolto, non sapevo di questa regola.
  5. 0

    Che non si può avere ricorsiva macro in C o C++.

    • bene..ho avuto il mio primo dubbio chiaro che non puoi avere ricorsiva macro. Che cosa circa l’errore nel mio codice di esempio in questione…???
    • Non puoi dire il tipo di errore che si ottiene, ma la pr utilizzato in modo ricorsivo in pr macro non ottenere espanso, e probabilmente i risultati in un “undefined function errore” o qualcosa del genere.

Lascia un commento