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.
En su caso particular. ptrdiff_t siempre se debe definir si incluye stddef.h –
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
Use una herramienta como cmake o autotools – szx