2011-02-02 14 views
9

Mi piacerebbe fare in modo che la compilazione di alcuni file fallisse se tentata dopo una certa data. La ragione per questo: ho trovato un paio di bug Y2K38 che non ho il tempo di risolvere adesso, ma vorrei prendere nota di loro e penso che sarebbe bello se la compilazione del modulo fallisse solo dopo, dire, 2020. (potrei essere pazzo, ma questo codice è di 20 anni ho il sospetto che potrebbe sopravvivere a un altro 30)preprocessore c - fallire se si compila dopo una certa data

+1

Non è il problema più che il programma smetterà di funzionare su 2038, non che smetterà di compilare? –

+8

A chi importa se non riesci a compilarlo dopo, per esempio, il 2020? Il problema è se la versione compilata è ancora in produzione da qualche parte nel 2038. Risolvi quella merda, pronto e falla distribuire. – jason

+4

Hai preso in considerazione un #warning? Li ho usati prima come poche cose da fare per il futuro. – whitey04

risposta

5

con GCC, si può fare qualcosa di simile al seguente:

void __attribute__((error("Whoa. It's the future"))) whoa_the_future(); 

void check_for_the_future() { 
    // "Feb 1 2011" 
    const char *now = __DATE__; 
    if (now[9] >= '2') 
     whoa_the_future(); 
} 

il modo questo funziona è che l'attributo error indica a GCC di generare un errore in fase di compilazione se qualsiasi chiamata a tale funzione viene lasciata nel codice dopo che tutti i codici di errore costante di GCC si sono piegati eliminazione, e passaggi simili sono stati eseguiti. Dal DATE è una costante in fase di compilazione, GCC può valutare l'istruzione if in fase di compilazione e rimuovere la chiamata .

Almeno un aspetto negativo è che questo dipende dalla ottimizzazione passaggi di GCC, e così non funzionerà a gcc -O0

Onestamente, si potrebbe essere meglio solo l'aggiunta di un controllo runtime da qualche parte e non riuscendo veloce.

+4

Entro il 2100, i compilatori sistemeranno automaticamente cose come 2038 bug. – aschepler

+3

@aschepler - Speriamo che risolveranno automaticamente 2038 bug entro il 2038. –

+0

@nelhage grazie, questo è interessante. Naturalmente, ho bisogno di questo sia in VS che in gcc :) Hai ragione, il controllo del runtime è probabilmente migliore. –

0

Una soluzione più generica che dovrebbe funzionare con la maggior parte dei compilatori. Dipende un po 'sul formato del DATA direttiva preprocessore

#define DIGIT(ch) (((ch)<'0'||(ch)>'9') ? 0 : ((ch)-'0')) 
#define YEAR (1000*DIGIT(__DATE__[7])+100*DIGIT(__DATE__[8])+10*DIGIT(__DATE__[9])+DIGIT(__DATE__[10])) 

#ifdef YEAR-2020>0 
#error too old 
#endif 
+0

'#ifdef YEAR-2038> 0'? –

+2

Sottoscrittore di array non funziona a livello del preprocessore. Scusate. –

+0

@R Penso di sì. Ho provato il suo codice e ANNO ottiene il valore corretto del 2011, ma non è chiaro come usarlo (per me). –

5

Invece di trattare con il formato imbarazzante del __DATE__ macro, perché non rotolare il proprio?

gcc -DTHIS_YEAR=`/bin/date +%Y` yourprogram.c 

Quindi il codice può utilizzare espressioni come #if THIS_YEAR >= 2020.

+0

oh, I così ... un po '. Un po 'troppo fragile. È probabile che il sistema di costruzione cambi nei prossimi 10 anni e questo si spezzerà. –

+1

@MK: puoi anche avere un '# if' che genera un' # error' se 'THIS_YEAR' non è definito, il che garantirà che le modifiche al sistema di build mantengano questa funzionalità. –

+0

Se l'avessi trovato in un sistema di compilazione, avrei semplicemente aggiunto '-DTHIS_YEAR = 2011' a' CFLAGS' ... :-) –

5

Ecco una soluzione orribile:

  1. In directory intestazione general-purpose del progetto, eseguire il seguente (Python) script:

    #!/usr/bin/python 
    
    months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 
          'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] 
    
    cutoff = 2020 
    #safety = 2025 
    
    for year in range(2011, cutoff): 
        for month in months: 
         for day in range(1, 32): 
          t = open("%s %2d %d" % (month, day, year), "w") 
          t.write("\n"); 
          t.close() 
    
    #for year in range(2011, cutoff): 
    # for month in months: 
    #  for day in range(1, 32): 
    #   t = open("%s %2d %d" % (month, day, year), "w") 
    #   t.write("#error \"Too old\"\n"); 
    #   t.close() 
    

    Rimuovere il commento le righe di commento-out per la produzione di una migliore diagnostica messaggi.

  2. Nei file che devono errore dopo la data limite, utilizzare questo:

    #include __DATE__ 
    

Ti sfido a utilizzare questo nel codice di produzione.

+0

questo sta sfuggendo di mano ma immagino sia quello che ho chiesto :) –

+0

Impressionante ! :-) LOL –

+0

+1 per: (1) farmi ridere, e (2) essere abbastanza sano di mente da includere la prima frase. –

1

__DATE__ non è la cosa giusta per un tale obiettivo:

If the date of translation is not available, an implementation-defined valid date shall be supplied.

Qualsiasi futuro rotto compilatore C che ancora implementa solo C99 :) e non uno qualsiasi dei suoi seguaci possono fissare la data a "Jan  1 1970" o fa avvolgere una volta oltre la data fatale nel 2038.

+0

In teoria, sì, questo è vero (e rido la frase "_still only_ implementa C99" - che sarà il giorno), ma in pratica la data interna di nessuno compilatore moderno sta per fallire prima 2038, e dal momento che l'OP vuole bene un avvertimento prima di quella data questo dovrebbe funzionare. Ma +1 per correttezza tecnica. –

+0

No, questo non è solo teorico.Qualcuno che proverà ancora a compilare una versione di codice in cui non è stato risolto in quel momento è molto probabile che utilizzi anche un compilatore non funzionante. In particolare, se l'implementatore del compilatore usa la stessa strategia e gli involucri del '__DATE__' del compilatore (che è legale). Quindi, in sostanza, '__DATE__' è la risposta sbagliata a una domanda sbagliata. –

Problemi correlati