2012-09-24 7 views
8

Se un compilatore ha un determinato tipo (ad esempio ptrdiff_t) come tipo incorporato, non voglio digitarlo di nuovo. So che il codice qui sotto non funziona correttamente che mi aspettavo.Come posso verificare che un determinato tipo sia già definito nel compilatore C?

#ifndef ptrdiff_t 
    typedef long int ptrdiff_t; 
#endif 

Come posso controllare un certo tipo è già definita nella C compilatore ?

+1

Nel tuo caso particolare. ptrdiff_t dovrebbe sempre essere definito se si include stddef.h –

+2

Essere in grado di testare il codice per l'esistenza e le proprietà di particolari definizioni è chiamato "reflection". I linguaggi di scripting tendono a supportare una piena riflessione, in parte perché è relativamente facile per i linguaggi di scripting. .NET e JVM supportano anche la riflessione. Per le lingue native, tuttavia, il supporto della riflessione in fase di esecuzione richiederebbe un sacco di codice eseguibile aggiuntivo. Alcune riflessioni in fase di compilazione possono essere supportate senza tale overhead, ma C non ha praticamente alcun supporto per la riflessione anche in fase di compilazione. – Steve314

+0

Usa uno strumento come cmake o autotools – szx

risposta

1

Nella tua domanda si è un po 'di confusione 2 cose diverse:

il costruito nel tipi, come int, float, ecc Questi sono i tipi Stnd e sono definiti è tutti i compilatori. Tipi come __int64 non sono standard, ma sono definiti in alcuni dei compilatori. Non devi fare nulla per usarli. Allo stesso tempo non puoi capire nel tuo codice se sono definiti o meno. Questo può essere scoperto solo dai doc sul compilatore. È possibile scrivere:

#ifdef MSVC 
     .... Microsoft specific code 
#else 
     .... Code for other compiler. 
#endif 

Questo approccio consente di creare una sorta di compiler independent environment.

Oltre ai tipi integrati, ci sono tipi che provengono dalle intestazioni. Alcune intestazioni sono costrutti quali:

#ifndef ptrdiff_t_DEFINED 
    #define ptrdiff_t_DEFINED 
    typedef long int ptrdiff_t; 
#endif 

Si noti che il defn le macro rimane a parte il defn del tipo. Non è possibile controllare se il tipo è definito o meno, ma è possibile verificare facilmente se la definizione è definita.

Quali intestazioni sono incluse nel codice che si desidera. Ciò significa che queste definizioni non sono in the compiler itself. Sono nel set di definizioni dell'attuale unità di traduzione. Per il compilatore hanno poca differenza dalle altre definizioni di tipo che scrivi nel tuo codice.

Alcune intestazioni del compilatore o del sistema per non avere "defn di protezione" come nell'esempio sopra. In questo caso, l'unica cosa che puoi fare è tenere traccia di quali header stanno arrivando e includere/non includere queste intestazioni, maby usando le tue guardie #ifdef attorno alle dichiarazioni #include.

5

Non c'è modo di farlo in generale. In alcuni casi potrebbe esserci una macro definita nello stesso momento del tipo che è possibile utilizzare.

Nel tuo esempio specifico, è possibile #include <stddef.h>, che deve sempre definire ptrdiff_t.

0

Poiché la ridefinizione di un costrutto riservato in linguaggio C genererebbe generalmente un errore in fase di compilazione, non è possibile controllarlo in generale. Se sei interessato (per processo accademico/di apprendimento), puoi scrivere un passaggio del compilatore di base per verificare le eccezioni/errori sul tuo programma C per rilevare se un tipo è riservato o meno.

4

Come altri hanno già detto, non c'è una buona soluzione generale a questo. I nomi dei tipi non sono visibili al preprocessore, quindi non è possibile utilizzare #ifdef per verificare la loro esistenza.

Ci sono un certo numero di soluzioni parziali, tuttavia, e variano a seconda di dove provengono i requisiti per un determinato tipo.

Esistono diverse versioni dello standard ISO C, rilasciate nel 1990, 1999 e 2011.Ogni nuovo standard (in teoria) sostituisce e sostituisce il precedente, e ognuno definisce alcuni nuovi tipi. Ad esempio le intestazioni standard 1999 C aggiunte <stdbool.h> e <stdint.h> e tipi bool, int32_t, ecc. Se si desidera utilizzare il tipo bool, ma si desidera comunque che il codice sia portatile per implementazioni che non supportano C99, è possibile eseguire un'operazione come:

#if defined(__STDC__) && __STDC_VERSION__ >= 199901L 
#include <stdbool.h> 
#else 
typedef enum { false, true } bool; 
#endif 

Il enum tipo non si comporta esattamente come quella di C99 built-in bool tipo, quindi è necessario essere un po 'attenti a come lo si utilizza.

Il tipo uintptr_t, definito in <stdint.h> è facoltativo. È un tipo senza segno che può contenere un valore di puntatore convertito void* senza perdita di informazioni; un'implementazione che non ha un tipo non firmato (ad esempio, perché i puntatori sono più grandi di qualsiasi tipo intero) non la fornirà. Non è possibile verificare direttamente per il tipo in sé, ma è possibile verificare per le macro che danno i suoi limiti:

#include <stdint.h> 

#ifdef UINTMAX_MAX 
/* uintmax_t exists */ 
#else 
/* uintmax_t doesn't exist */ 
#endif 

Potrebbe essere necessario avvolgere questo in un test per __STDC__ e __STDC_VERSION__ se non si può assumere C99 o meglio.

Il tipo long long è un tipo predefinito (non parte della libreria), aggiunto in C99. Anche in questo caso, non è possibile verificare direttamente, ma è possibile verificare per le macro che definiscono i suoi confini:

#include <limits.h> 

#ifdef LLONG_MAX 
/* long long exists */ 
#else 
/* long long *probably* doesn't exist */ 
#endif 

Infine, ci sono cose che non si possono fare direttamente in C, ma che si può fare come parte del processo di creazione del tuo programma. Ad esempio, POSIX definisce un tipo pid_t nell'intestazione specifica POSIX <unistd.h> (è il tipo di identificativo di processo restituito dalla funzione getpid()). Non si può condizionale includere un'intestazione - ma è possibile scrivere un piccolo programma che non riuscirà a compilare se l'intestazione non esiste:

#include <unistd.h> 
pid_t dummy; 

Come parte del processo di generazione, provare a compilare questo file. Se riesce, aggiungi una riga come

#define HAVE_PID_T 

in un'intestazione di configurazione; se fallisce, aggiungere una linea come

#undef HAVE_PID_T 

Nel codice sorgente, è possibile scrivere qualcosa come:

#include "config.h" 
#ifdef HAVE_PID_T 
#include <unistd.h> 
/* pid_t exists */ 
#else 
/* pid_t doesn't exist */ 
#endif 

GNU Autoconf fornisce un modo per automatizzare questo tipo di test, ma è stato criticato per essere troppo complesso e ingombrante

Tutto ciò presuppone che, una volta determinato se esiste un tipo, è possibile fare qualcosa di utile con tali informazioni. Per alcuni tipi, come bool, è possibile implementare un'alternativa quasi equivalente. Per pid_t, d'altra parte, probabilmente non c'è un buon ripiego, a meno che non siate semplicemente #ifdef a estrarre tutto il codice che tratta i processi. Se il tuo programma non funziona su un sistema che non ha pid_t e getpid(), potrebbe essere meglio scrivere semplicemente codice che presume che esistano. Se si tenta di compilare il codice su un sistema che non li fornisce, non verrà immediatamente compilato e potrebbe essere la cosa migliore che si possa fare.

Problemi correlati