Detección de compilación de 64 bits en C

10 minutos de lectura

avatar de usuario
Daniel

¿Hay una macro C o algún tipo de forma en que pueda verificar si mi programa C se compiló como 64 bits o 32 bits en tiempo de compilación en C?

Compilador: GCC Sistemas operativos en los que necesito hacer las comprobaciones: Unix/Linux

Además, ¿cómo podría verificar al ejecutar mi programa si el sistema operativo es compatible con 64 bits?

  • Echa un vistazo a la siguiente pregunta. Describe el uso de la __LP__ directiva de preprocesador gcc

    – mdec

    11 de marzo de 2011 a las 12:28

  • Por qué quieres saber?

    – Fred Foo

    11 de marzo de 2011 a las 12:33

  • ¿Desea examinar un archivo ejecutable binario y determinar qué opciones del compilador se usaron para crear ese archivo?

    – pmg

    11 de marzo de 2011 a las 12:44

  • Espera un segundo… ¿quieres decir que ya tienes el binario y quieres comprobarlo? (Ya que mencionaste “fue compilado”) O durante tiempo de compilación (ya que mencionó la macro C)?

    – Derick Schoonbee

    11 de marzo de 2011 a las 12:46

  • @Daniel: entiendo lo que quieres hacer, la pregunta es solo por qué. Su pregunta no es del todo válida ya que “arquitectura de 64 bits” no es un término muy bien definido (¿quiere registros de 64 bits, bus de datos de 64 bits, punteros de 64 bits?), ¿Su programación es solo para x86? o portátil…

    – Fred Foo

    11 de marzo de 2011 a las 12:50

Dado que etiquetó este “gcc”, intente

#if __x86_64__
/* 64-bit */
#endif

  • Otra macro para probar es ‘_____LP64_____’, que funcionará en una arquitectura que no sea x86-64.

    -Gunther Piez

    11 de marzo de 2011 a las 12:35


  • Probar cualquier macro que comience con _[A-Z] o __ es casi seguro que es la respuesta incorrecta.

    – R.. GitHub DEJA DE AYUDAR A ICE

    11 de marzo de 2011 a las 13:15

  • @R..: No, es casi seguro que el Correcto responder. Las macros que comienzan con _[A-Z] o __ están reservados por la implementación (es decir, el compilador/preprocesador), lo que significa que no puede definirlos usted mismo, pero ciertamente puede probar su existencia para consultar la implementación.

    – Adam Rosenfield

    4 de agosto de 2011 a las 15:29

  • @Adam: Y el resultado solo será significativo en algunas implementaciones. Si, en cambio, prueba un estándar macro como UINTPTR_MAX, es confiable en todas las implementaciones. (Sugerencia: una implementación válida podría predefinir felizmente __LP64__ en máquinas de 32 bits, o como un ejemplo aún más extremo, podría tratar todos nombres de macros que comienzan con __ definidos a menos que estén explícitamente indefinidos).

    – R.. GitHub DEJA DE AYUDAR A ICE

    4 de agosto de 2011 a las 16:39

  • @R..: OTOH, el estándar C99 garantiza que uintptr_t sea lo suficientemente grande como para contener un puntero, pero no garantiza que no sea más grande de lo necesario. Una implementación podría usar un uintptr_t de 64 bits aunque todos los punteros sean de 32 bits. O, para el caso, dado que uintptr_t es opcional en C99, es posible que su macro “estándar” no se defina de todos modos.

    – Anomia

    4 de agosto de 2011 a las 17:07

Aquí está la prueba correcta y portátil que no asume x86 ni nada más:

#include <stdint.h>
#if UINTPTR_MAX == 0xffffffff
/* 32-bit */
#elif UINTPTR_MAX == 0xffffffffffffffff
/* 64-bit */
#else
/* wtf */
#endif

  • Sé que esta pregunta es para C, pero dado que se mezcla con (o se incluye de) C++ la mayor parte del tiempo, aquí hay una advertencia de C++: C99 requiere que para obtener macros de límite definidas en C++, debe tener __STDC_LIMIT_MACROS definido antes de incluir el encabezado. Como es posible que ya se haya incluido, la única forma de garantizar la definición correcta es obligar al cliente a incluirla siempre como primer encabezado en el archivo de origen, o agregar -D__STDC_LIMIT_MACROS a sus opciones de compilación para todos los archivos.

    – Alex B.

    11 de marzo de 2011 a las 13:41

  • La portabilidad está teóricamente limitada por el hecho de que uintptr_t es un tipo opcional. Sin embargo, sospecho que sería perverso para una implementación de 64 bits omitirlo, ya que unsigned long long es un tipo entero lo suficientemente grande.

    –Steve Jessop

    4 de agosto de 2011 a las 15:16


  • Mi opinión es que un sistema que omite uintptr_t probablemente tiene muy buenas razones para hacerlo (un modelo de memoria muy patológico o al menos atípico, por ejemplo) y que cualquier suposición hecha sobre la base de que este es “un sistema de 32 bits” o “un sistema de 64 bits” sería inválida en tal implementación. Como tal, el caso “wtf” en mi respuesta probablemente debería contener #error o bien un código hiperportátil que es completamente independiente de las suposiciones tradicionales sobre modelos de memoria, tamaños de letra, etc.

    – R.. GitHub DEJA DE AYUDAR A ICE

    4 de agosto de 2011 a las 15:35

  • Esto no funciona en los núcleos PAE de Linux. Los núcleos con PAE activado son de 32 bits pero pueden abordar la RAM como un sistema de 64 bits. Este código determina la arquitectura comprobando la RAM máxima direccionable. Una máquina de núcleo PAE de 32 bits se vería como de 64 bits con esto, por lo que el código fuente insertado (posiblemente alguna instrucción de ensamblador en línea) no funcionaría.

    – Kenyakorn Ketsombut

    16 de junio de 2014 a las 3:27

  • desde mi perspectiva, cualquier arquitectura que pueda hacer aritmética de 64 bits de forma nativa es una arquitectura de 64 bits. Y hay varias arquitecturas con solo un bus de direcciones de 24 bits, pero aún se las llama “32 bits” porque sus registros son de 32 bits. Lo mismo para las MCU de 8 bits, aunque sus buses de direcciones suelen ser de 14 a 16 bits o más.

    – phuclv

    24 de febrero de 2015 a las 6:28

Una fácil que hará que el abogado de idiomas se estremezca.

if(sizeof (void *) * CHARBIT == 64) {
...
}
else {
...
}

Como es una expresión constante, un compilador optimizador descartará la prueba y solo colocará el código correcto en el ejecutable.

  • Por lo general, es cierto, pero por favor, deje de hacer afirmaciones como “… para que un compilador optimizador…”. El preprocesador es el preprocesador y, a menudo, el código que sigue a “else” no se compilará cuando la condición sea verdadera.

    – Tomasz Gandor

    8 de agosto de 2014 a las 18:52

  • No veo qué tiene que ver el preprocesador con nada. El OP solicitó un método para detectar el modelo de mem utilizado (64 o 32 bits), no solicitó una solución de preprocesador. Nadie preguntó una forma de reemplazar la compilación condicional. Por supuesto, mi solución requiere que ambas ramas sean sintácticamente correctas. El compilador los compilará siempre. Si el compilador está optimizando, eliminará el código generado, pero incluso si no lo hace, no hay problema con eso. ¿Te importa elaborar lo que quieres decir?

    – Patrick Schlüter

    9 de agosto de 2014 a las 10:27


  • Está bien, tienes razón. La redacción exacta era “una macro C o algún tipo de forma”. No me di cuenta de “algún tipo de manera” al principio.

    – Tomasz Gandor

    09/08/2014 a las 16:00

  • @ShelbyMooreIII: Ummmmm… ¿Disculpe? La distinción entre un objetivo de 32 bits y de 64 bits no tiene absolutamente nada que ver con el tamaño de int (de hecho, su tamaño difiere por ejemplo, en LP64 como se usa en Linux/BSD frente a LLP64 como se usa en Windows, mientras que ambos son claramente de 64 bits). Tampoco tiene nada que ver con qué tan rápido un compilador puede optimizar una operación en particular (o qué tan rápido funciona Javascript).

    – Damon

    10 de marzo de 2016 a las 16:29

  • No detecta ABI ILP32 en arquitecturas de 64 bits, por ejemplo la ABI x32 de Linux o la AArch64 ILP32 ITB. Son punteros de 32 bits en modo de 64 bits. Entonces long long sigue siendo eficiente en esos objetivos, a diferencia de las CPU de 32 bits donde los enteros de 64 bits toman 2 instrucciones por operación y 2 registros.

    – Peter Cordes

    28 de marzo de 2018 a las 16:35

Una solución neutral para el compilador y la plataforma sería esta:

// C
#include <stdint.h>

// C++
#include <cstdint>

#if INTPTR_MAX == INT64_MAX
// 64-bit
#elif INTPTR_MAX == INT32_MAX
// 32-bit
#else
#error Unknown pointer size or missing size macros!
#endif

Evite macros que comiencen con uno o más guiones bajos. No son estándar y pueden faltar en su compilador/plataforma.

avatar de usuario
alex b

Use una macro específica del compilador.

No sé a qué arquitectura se dirige, pero dado que no la especifica, asumiré máquinas Intel comunes y corrientes, por lo que lo más probable es que esté interesado en probar Intel x86 y AMD64.

Por ejemplo:

#if defined(__i386__)
// IA-32
#elif defined(__x86_64__)
// AMD64
#else
# error Unsupported architecture
#endif

Sin embargo, prefiero ponerlos en el encabezado separado y definir mi propia macro neutral del compilador.

  • Use una macro estándar (vea mi respuesta), no una específica del compilador.

    – R.. GitHub DEJA DE AYUDAR A ICE

    11 de marzo de 2011 a las 13:17

  • @R.. Sí, lo sé, y se rompe con el código C++, por lo que generalmente me quedo con los específicos del compilador.

    – Alex B.

    11 de marzo de 2011 a las 13:41


  • Entonces usa ULONG_MAX en lugar de UINTPTR_MAX. En cualquier sistema unixy del mundo real serán iguales. Seguramente es mucho más portátil para asumir long y los punteros son del mismo tamaño que para suponer que están presentes algunas macros del compilador en particular.

    – R.. GitHub DEJA DE AYUDAR A ICE

    11 de marzo de 2011 a las 20:38

  • @R.. Y todavía está mal en Windows de 64 bits. Prefiero que mi código no se compile, en lugar de compilar silenciosamente algo incorrecto.

    – Alex B.

    31 de marzo de 2011 a las 23:35

  • Estoy votando negativo. Ver mi respuesta por la razón. En términos generales, no se puede confiar en ninguno de estos escenarios para dar una indicación confiable de si un espacio de direcciones de 64 bits y una aritmética de 64 bits no emulada están disponibles, por lo que son básicamente inútiles excepto en el contexto de un sistema de compilación que no es agnóstico. Por lo tanto, se prefiere establecer macros de compilación para que el sistema de compilación pueda seleccionar qué variante se compila.

    – Shelby Moore III

    24 de noviembre de 2015 a las 0:12

avatar de usuario
jonathan reinhart

El mismo GLIBC usa esto (en inttypes.h):

#if __WORDSIZE == 64

  • Use una macro estándar (vea mi respuesta), no una específica del compilador.

    – R.. GitHub DEJA DE AYUDAR A ICE

    11 de marzo de 2011 a las 13:17

  • @R.. Sí, lo sé, y se rompe con el código C++, por lo que generalmente me quedo con los específicos del compilador.

    – Alex B.

    11 de marzo de 2011 a las 13:41


  • Entonces usa ULONG_MAX en lugar de UINTPTR_MAX. En cualquier sistema unixy del mundo real serán iguales. Seguramente es mucho más portátil para asumir long y los punteros son del mismo tamaño que para suponer que están presentes algunas macros del compilador en particular.

    – R.. GitHub DEJA DE AYUDAR A ICE

    11 de marzo de 2011 a las 20:38

  • @R.. Y todavía está mal en Windows de 64 bits. Prefiero que mi código no se compile, en lugar de compilar silenciosamente algo incorrecto.

    – Alex B.

    31 de marzo de 2011 a las 23:35

  • Estoy votando negativo. Ver mi respuesta por la razón. En términos generales, no se puede confiar en ninguno de estos escenarios para dar una indicación confiable de si un espacio de direcciones de 64 bits y una aritmética de 64 bits no emulada están disponibles, por lo que son básicamente inútiles excepto en el contexto de un sistema de compilación que no es agnóstico. Por lo tanto, se prefiere establecer macros de compilación para que el sistema de compilación pueda seleccionar qué variante se compila.

    – Shelby Moore III

    24 de noviembre de 2015 a las 0:12

avatar de usuario
HaseeB Mir

Utilizar esta UINTPTR_MAX valor para verificar el tipo de compilación.

#include <stdio.h>
#include <limits.h>

#if UINTPTR_MAX == 0xffffffffffffffffULL               
# define BUILD_64   1
#endif

int main(void) {

    #ifdef BUILD_64
    printf("Your Build is 64-bit\n");

    #else
    printf("Your Build is 32-bit\n");

    #endif
    return 0;
}

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad