¿Qué preprocesador multiplataforma define? (__WIN32__ o __WIN32 o WIN32)?

9 minutos de lectura

avatar de usuario
Matemáticas

a menudo veo __WIN32, WIN32 o __WIN32__. Supongo que esto depende del preprocesador utilizado (ya sea uno de Visual Studio o GCC, etc.).

¿Ahora tengo que verificar primero el sistema operativo y luego el compilador usado? Estamos usando aquí G ++ 4.4.x, Visual Studio 2008 y Xcode (que supongo que es un gcc nuevamente) y ATM que estamos usando solo __WIN32__, __APPLE__ y __LINUX__.

  • _WIN32 es sistemática, más a menudo que otras grafías. Ver sourceforge.net/p/predef/wiki/SistemasOperativos . La buena práctica es probar lo que es relevante en cada situación (SO, archi, compilador…) y no probar uno por el otro. Y tampoco redefinir el tuyo propio.

    – Sandburg

    10 de enero de 2019 a las 8:41


avatar de usuario
Charfacia

Este artículo responde a tu pregunta:

El artículo es bastante largo e incluye tablas que son difíciles de reproducir, pero esta es la esencia:

Puede detectar un sistema operativo de estilo Unix con:

#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))
    /* UNIX-style OS. ------------------------------------------- */

#endif

Una vez que sepa que es Unix, puede encontrar si es POSIX y la versión POSIX con:

#include <unistd.h>
#if defined(_POSIX_VERSION)
    /* POSIX compliant */
#endif

Puede buscar sistemas derivados de BSD con:

#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#include <sys/param.h>
#if defined(BSD)
    /* BSD (DragonFly BSD, FreeBSD, OpenBSD, NetBSD). ----------- */

#endif
#endif

y Linux con:

#if defined(__linux__)
    /* Linux  */
#endif

y los sistemas operativos de Apple con

#if defined(__APPLE__) && defined(__MACH__)
    /* Apple OSX and iOS (Darwin) */
#include <TargetConditionals.h>
#if TARGET_IPHONE_SIMULATOR == 1
    /* iOS in Xcode simulator */
#elif TARGET_OS_IPHONE == 1
    /* iOS on iPhone, iPad, etc. */    
#elif TARGET_OS_MAC == 1
    /* OS X */
#endif
#endif

Ventanas con Cygwin

#if defined(__CYGWIN__) && !defined(_WIN32)
    /* Cygwin POSIX under Microsoft Windows. */
#endif

Y Windows no POSIX con:

#if defined(_WIN64)
    /* Microsoft Windows (64-bit) */
#elif defined(_WIN32)
    /* Microsoft Windows (32-bit) */
#endif

El artículo completo enumera los siguientes símbolos y muestra qué sistemas los definen y cuándo: _AIX, __APPLE__, __CYGWIN32__, __CYGWIN__, __DragonFly__, __FreeBSD__, __gnu_linux, hpux, __hpux, linux, __linux, __linux__, __MACH__, __MINGW32__, __MINGW64__, __NetBSD__, __OpenBSD__, _POSIX_IPV6, _POSIX_MAPPED_FILES, _POSIX_SEMAPHORES, _POSIX_THREADS, _POSIX_VERSION, sun, __sun, __SunOS, __sun__, __SVR4, __svr4__, TARGET_IPHONE_SIMULATOR, TARGET_OS_EMBEDDED, TARGET_OS_IPHONE, TARGET_OS_MAC, UNIX, unix, __unix, __unix__, WIN32, _WIN32, __WIN32, __WIN32__, WIN64, _WIN64, __WIN64, __WIN64__, WINNT, __WINNT, __WINNT__.

A Artículo relacionado (enlace archive.org) cubre la detección de compiladores y versiones de compiladores. Enumera los siguientes símbolos: __clang__, __GNUC__, __GNUG__, __HP_aCC, __HP_cc, __IBMCPP__, __IBMC__, __ICC, __INTEL_COMPILER, _MSC_VER, __PGI, __SUNPRO_C, __SUNPRO_CC para detectar compiladores, y __clang_major__, __clang_minor__, __clang_patchlevel__, __clang_version__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__, __GNUC__, __GNUG__, __HP_aCC, __HP_cc, __IBMCPP__, __IBMC__, __ICC, __INTEL_COMPILER, __INTEL_COMPILER_BUILD_DATE, _MSC_BUILD, _MSC_FULL_VER, _MSC_VER, __PGIC_MINOR__, __PGIC_PATCHLEVEL__, __PGIC__, __SUNPRO_C, __SUNPRO_CC, __VERSION__, __xlC_ver__, __xlC__, __xlc__ para detectar versiones del compilador.

  • Los enlaces pueden romperse, y solo publico el enlace sin ninguna explicación que considero que no es un buen estilo de control de calidad. Incluso cuando esto sería sólo un comentario. Intenta resumir el artículo.

    – Matemáticas

    8 de octubre de 2014 a las 6:51


  • Buena llamada. Actualicé el artículo para brindar muchos más detalles y también proporcioné enlaces a archive.org para manejar mejor la desaparición del sitio.

    – Charfacia

    15/10/2014 a las 18:55

Depende de lo que estés tratando de hacer. Puede verificar el compilador si su programa quiere hacer uso de algunas funciones específicas (de la cadena de herramientas gcc, por ejemplo). Puede verificar el sistema operativo (_WINDOWS, __unix__) si desea usar algunas funciones específicas del sistema operativo (independientemente del compilador, por ejemplo, CreateProcess en Windows y bifurcación en Unix).

Macros para Visual C

Macros para gcc

Debes consultar la documentación de cada compilador para poder detectar las diferencias a la hora de compilar. Recuerdo que la cadena de herramientas gnu (gcc) tiene algunas funciones en la biblioteca C (biblioteca) que no están en otras cadenas de herramientas (como Visual C, por ejemplo). De esta forma si quieres usar esas funciones por comodidad entonces debes detectar que estás usando GCC, por lo que el código que debes usar sería el siguiente:

#ifdef __GNUC__
// do my gcc specific stuff
#else
// ... handle this for other compilers
#endif

No veo por qué tienes que hacerlo. Es posible que deba recordar especificar la definición manualmente en la línea de comandos de su compilador, pero eso es todo. Para que conste, la definición de Visual Studio es _WIN32 (con un guión bajo) en lugar de __WIN32. Si no está definido, entonces no está definido y no importará.

  • Entonces podría escribir el #ifdef __WIN32__ solo una vez y no #ifdef WIN32 || __WIN32 || __WIN32__

    – Matemáticas

    7 de junio de 2010 a las 14:53

  • @brubelsabs: Sí, pero debe recordar ingresar la definición del preprocesador usted mismo en la línea de comandos si decide usar otro compilador.

    – Billy ONeal

    7 de junio de 2010 a las 16:09

  • hasta donde se _WIN32 está definido para todos los compiladores (modernos) de Windows (excepto WinCE, por supuesto). No hace falta que lo definas tú mismo…

    – rubenvb

    31 de enero de 2011 a las 19:43

  • @math: Tu #ifdef-La expresión es incorrecta. Debería ser #if defined(WIN32) || defined(__WIN32) || defined(__WIN32__). Consulte las directivas del preprocesador C y los operadores booleanos como referencia.

    – Inspeccionable

    12/08/2014 a las 12:30

  • @IInspectable: O tal vez #if WIN32 || _WIN32 || __WIN32__. Los nombres no definidos se tratan como cero. La pregunta es qué se debe hacer en caso de #define _WIN32 0.

    – Ben Voigt

    15/10/2014 a las 18:58


avatar de usuario
silmet

Reconstruí mi respuesta… Maldición, editando loco :P:

No es necesario utilizar una partical. Y probablemente para MacOSX, Linux y otros similares a Unix, no necesita usar ninguno.

El más popular es (hasta donde Google dice la verdad) es _WIN32.

nunca defínalo “a mano” en su código fuente. Se define de una de estas formas:
como una marca de preprocesador/compilador de línea de comandos (como g++ -D _WIN32)
o está predefinido por el propio compilador (la mayoría de los compiladores de Windows predefinen _WIN32y a veces otras como WIN32 o _WIN32_ también. — Entonces no necesita preocuparse por definirlo en absoluto, el compilador hace todo el trabajo.


Y mi vieja respuesta:

No ‘tienes que’ nada. Es solo por compatibilidad multiplataforma. A menudo, la versión del código para todos los similares a Unix (incluidos Linux, MacOSX, BSD, Solaris…) y otras plataformas POSIX serán completamente iguales y debe haber algunos cambios para Windows. Por lo tanto, las personas escriben su código generalmente para los gustos de Unix y colocan algunas partes solo de Windows (por ejemplo, instrucciones de DirectX, rutas de archivos similares a Windows …) entre #ifdef _WIN32 y #endif.

Si tiene algunas piezas, por ejemplo. Solo el sistema X-Window, o solo MacOS, haces algo similar con algo como #ifdef X_WINDOW o #ifdef MACOS. Luego, debe establecer una definición de preprocesador adecuada durante la compilación (con gcc usando el indicador -D, como por ejemplo. gcc -D _WIN32).

Si no escribe ningún código dependiente de la plataforma, entonces no necesita preocuparse por tal #ifdef, #else, #endif bloques Y la mayoría de los compiladores/preprocesadores de Windows AFAIK han predefinido algunos símbolos como _WIN32 (más popular, en la medida en que Google dice la verdad), WIN32, _WIN32_etc. Así que compilarlo en Windows lo más probable es que no necesite hacer nada más que simplemente compilar.

Suspiro, no confíe en nada del compilador, especifique para qué plataforma está construyendo en su Makefile. En pocas palabras, cualquier cosa que comience con _ depende de la implementación y no es portátil.

Probé su método una vez, en un proyecto muy grande, y entre Sun-C++ y GCC, decidimos ir con el control de Makefile en lugar de tratar de deducir qué iban a hacer los compiladores.

  • Puede crear contenedores para diferentes comportamientos y usar esos contenedores. De esta manera, se manejan las diferencias de plataforma/compilador en solo unos pocos archivos fuente, lo que (en mi opinión) es mejor que lidiar con archivos MAKE para cada plataforma.

    – EN S

    7 de junio de 2010 a las 15:23

  • Tienes un punto válido. Sin embargo, no puedo concebir una situación en la que admita múltiples plataformas y no esté utilizando archivos Make de algún tipo (gmake/cmake/qmake) de todos modos. Las definiciones de la biblioteca de Windows para link.exe no son las mismas que gcc -L -l. Tampoco lo son las configuraciones de optimización del compilador. Prefiero tratar con mis banderas de plataforma en un Makefile (o algunos por inclusión) que tener que recordar incluir platform_magic.h en cada encabezado/archivo fuente. Boost lo hace a su manera: en boost/system/config.hpp determina en qué plataforma se está ejecutando. Tendremos que estar de acuerdo en no estar de acuerdo. 😀

    – Chris K.

    7 de junio de 2010 a las 16:49

  • Puede crear contenedores para diferentes comportamientos y usar esos contenedores. De esta manera, se manejan las diferencias de plataforma/compilador en solo unos pocos archivos fuente, lo que (en mi opinión) es mejor que lidiar con archivos MAKE para cada plataforma.

    – EN S

    7 de junio de 2010 a las 15:23

  • Tienes un punto válido. Sin embargo, no puedo concebir una situación en la que admita múltiples plataformas y no esté utilizando archivos Make de algún tipo (gmake/cmake/qmake) de todos modos. Las definiciones de la biblioteca de Windows para link.exe no son las mismas que gcc -L -l. Tampoco lo son las configuraciones de optimización del compilador. Prefiero tratar con mis banderas de plataforma en un Makefile (o algunos por inclusión) que tener que recordar incluir platform_magic.h en cada encabezado/archivo fuente. Boost lo hace a su manera: en boost/system/config.hpp determina en qué plataforma se está ejecutando. Tendremos que estar de acuerdo en no estar de acuerdo. 😀

    – Chris K.

    7 de junio de 2010 a las 16:49

¿Ha sido útil esta solución?