2012-09-24 49 views
8

Si un compilador tiene un cierto tipo (por ejemplo, ptrdiff_t) como un tipo incrustado, no quiero volver a escribirlo. Sé que el código a continuación no funciona correctamente de lo que esperaba.¿Cómo puedo verificar que cierto tipo ya esté definido en el compilador de C?

#ifndef ptrdiff_t 
    typedef long int ptrdiff_t; 
#endif 

¿Cómo puedo comprobar un determinado tipo ya está definido en el C compilador?

+1

En su caso particular. ptrdiff_t siempre se debe definir si incluye stddef.h –

+2

Ser capaz de probar en código la existencia y las propiedades de definiciones particulares se denomina "reflexión". Los lenguajes de scripting tienden a respaldar la reflexión total, en parte porque es relativamente fácil para los lenguajes de scripting. .NET y JVM también apoyan la reflexión. Para los idiomas nativos, sin embargo, el soporte de la reflexión en tiempo de ejecución requeriría una gran cantidad de código ejecutable adicional. Algunas reflexiones en tiempo de compilación pueden soportarse sin esa sobrecarga, pero C prácticamente no tiene soporte de reflexión incluso en tiempo de compilación. – Steve314

+0

Use una herramienta como cmake o autotools – szx

Respuesta

1

En su pregunta usted es un poco confuso 2 cosas diferentes:

el construido en tipos, como int, float, etc. Estos son los tipos STND y se definen es todos los compiladores. Los tipos como __int64 no son estándar, pero están definidos en algunos de los compiladores. No necesita hacer nada para usarlos. Al mismo tiempo, no puede figurar en su código si están definidos o no. Esto se puede deducir solo de los documentos del compilador. Se puede escribir:

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

Este enfoque permite crear una especie de compiler independent environment.

Además de los tipos incorporados, hay tipos que provienen de los encabezados. Algunas de las cabeceras tienen construcciones como:

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

Tenga en cuenta que la defn macroprocessor se mantiene aparte de la defn del tipo. No puede verificar si el tipo está definido o no, pero puede verificar fácilmente si la definición está definida.

Qué encabezados están incluidos en su código que usted mismo se merece. Esto significa que estas definiciones no son in the compiler itself. Están en el conjunto de definiciones de la unidad de traducción actual. Para el compilador tienen poca diferencia con otras definiciones de tipo que escribe en su propio código.

Algunos encabezados de compilador o sistema no tienen "guarding defns" como en el ejemplo anterior. En este caso, lo único que puede hacer es rastrear desde qué encabezados vienen e incluir/no incluir estos encabezados, maby usando sus propias guardias #ifdef alrededor de las declaraciones #include.

5

No hay forma de hacerlo en general. En algunos casos, puede haber una macro definida al mismo tiempo que el tipo que puede usar.

En su ejemplo particular, puede #include <stddef.h>, que siempre debe definir ptrdiff_t.

0

Como la redefinición de un constructo reservado en lenguaje C generalmente llevaría a un error de tiempo de compilación, no es posible verificarlo en general. Si está interesado (para el proceso académico/de aprendizaje), puede escribir un pase de compilación básico para verificar excepciones/errores en su programa C para detectar si un tipo está reservado o no.

4

Como han dicho otros, no hay una buena solución general para esto. Los nombres de tipos no son visibles para el preprocesador, por lo que no puede usar #ifdef para probar su existencia.

Existen varias soluciones parciales, sin embargo, varían según de dónde provienen los requisitos para un tipo determinado.

Existen varias versiones del estándar ISO C, emitidas en 1990, 1999 y 2011.Cada nuevo estándar (en teoría) reemplaza y reemplaza al anterior, y cada uno define algunos tipos nuevos. Por ejemplo, los encabezados agregados estándar 1999 C <stdbool.h> y <stdint.h>, y los tipos bool, int32_t, etc. Si desea utilizar el tipo bool, pero aún desea que su código sea portátil para implementaciones que no son compatibles con C99, puede hacer algo como:

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

El enum tipo no se comporta exactamente como de C99 incorporada bool tipo, por lo que necesita para ser un poco cuidadoso en la forma en que lo utilice.

El tipo uintptr_t, definido en <stdint.h> es opcional. Es un tipo sin signo que puede contener un valor de puntero void* convertido sin pérdida de información; una implementación que no tenga ese tipo sin signo (digamos, porque los punteros son más grandes que cualquier tipo de entero) no lo proporcionará. No se puede probar directamente para el tipo en sí, pero se puede probar para las macros que dan sus límites:

#include <stdint.h> 

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

Puede que tenga que terminar con esto de una prueba para __STDC__ y __STDC_VERSION__ si usted no puede asumir C99 o mejor.

El tipo long long es un tipo predefinido (que no forma parte de la biblioteca), agregado en C99. Una vez más, no se puede probar directamente, pero se puede probar para las macros que definen sus límites:

#include <limits.h> 

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

Por último, hay cosas que no se pueden hacer directamente en C, pero que se puede hacer tan parte del proceso de compilación de tu programa. Por ejemplo, POSIX define un tipo pid_t en el encabezado específico de POSIX <unistd.h> (es el tipo de un identificador de proceso, devuelto por la función getpid()). No puede incluir una cabecera condicional - pero se puede escribir un pequeño programa que va a dejar de compilar si la cabecera no existe:

#include <unistd.h> 
pid_t dummy; 

Como parte de su proceso de construcción, intenta compilar este archivo. Si tiene éxito, añadir una línea como

#define HAVE_PID_T 

a una cabecera de configuración; si falla, añada una línea como

#undef HAVE_PID_T 

En su código fuente, a continuación, puede escribir algo como:

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

GNU Autoconf proporciona una manera de automatizar este tipo de prueba, pero ha sido criticado por siendo excesivamente complejo e inmanejable.

Todo esto supone que, una vez que haya determinado si existe un tipo, puede hacer algo útil con esa información. Para algunos tipos, como bool, puede implementar una alternativa casi equivalente. Para pid_t, por otro lado, es probable que no haya una buena alternativa, a menos que simplemente #ifdef elimine todo el código que trata con los procesos. Si su programa simplemente no va a funcionar en un sistema que no tiene pid_t y getpid(), podría ser mejor escribir código que asume que existen. Si intenta compilar su código en un sistema que no los proporciona, inmediatamente no podrá compilar, y eso puede ser lo mejor que puede hacer.

Cuestiones relacionadas