2009-04-09 20 views
18

En una aplicación que mantengo, hemos encontrado un problema con las limitaciones del descriptor de archivo que afecta a stdlib. Este problema solo afecta a la versión de 32 bits de la lib estándar.#ifdef para plataforma de 32 bits

He ideado una solución para mi código y me gustaría implementarlo, pero solo cuando compilo para el ejecutable de 32 bits. ¿Qué símbolo del preprocesador puedo #ifdef para determinar si el código se está compilando para un objetivo de 32 o 64 bits?

EDITAR

Lo sentimos, no mencionó, el código es multiplataforma, Linux, Windows, Solaris y algunos otros sabores de Unix, en su mayoría utilizando GCC para su compilación. ¿Algún estándar de facto que pueda usar multiplataforma?

EDIT 2

he encontrado algunas definiciones "__ILP23" y "__LP64" que parece que pueden funcionar ... una discusión here explica el fondo en la plataforma UNIX. Alguien tiene alguna experiencia con el uso de estas define? ¿Esto va a ser útil?

+0

Depende de la plataforma. Diferentes sistemas operativos usan #defines diferentes. Si tienes suerte, Boost tiene una envoltura portátil escondida en alguna parte. De lo contrario, solo deberá verificar los específicos de la plataforma. ¿A qué plataforma estás corriendo por cierto? – jalf

+0

Se editó la pregunta ... el código se dirige principalmente a Windows, Solaris y Linux, y las partes también se ejecutan en AIX y HP-UX. – veefu

+0

Solo una idea: # if sizeof (int) == 64 – mmmmmmmm

Respuesta

15

No estoy seguro de si existe una #if def universal que sea apropiada. El estándar de C++ casi seguro no define uno. Sin embargo, hay plataforma spcefic.

Por ejemplo, Windows

#if _WIN64 
// 64 bit build 
#else 
// 32 bit build 
#endif 

EDITAR OP mencionado esto es una cruz compilar entre Windows y no Windows utilizando GCC y otros compiladores

No hay macro universal que se puede utilizar para todas las plataformas y compiladores. Sin embargo, un poco de magia preprocesadora puede hacer el truco. Suponiendo que solo está trabajando en chips x86 y amd64, lo siguiente debería ser el truco. Se puede ampliar fácilmente para otras plataformas, aunque

#if _WIN64 || __amd64__ 
#define PORTABLE_64_BIT 
#else 
#define PORTABLE_32_BIT 
#endif 
+0

Ok, suena así, combinado con alguna investigación de gcc por los comentarios de Chris puede hacer el truco. +1 a los dos. – veefu

4

Se puede comprobar un tipo conocido para su tamaño, por ejemplo. sizeof (int *) == 4 para una plataforma de 32 bits.

Como sizeof se conoce en tiempo de compilación que creen un

if(sizeof(int*) == 4) 
{ 
    ... 
} 

debe hacer el truco

Editar: los comentarios son correctas, es necesario utilizar un habitual si, # si no va a funcionar.

Si está utilizando C++ Podría crear código de plantilla y dejar que el compilador elija la especialización para usted en función de la llamada sizeof(). Si compila para una plataforma de 32 bits, el compilador solo instanciaría el código para la plataforma de 32 bits. Si compila para una plataforma de 654 bits, el compilador solo instanciaría el código para la plataforma de 64 bits.

+0

Sin embargo, esto no funcionará para un #ifdef. sizeof es el tiempo de compilación, mientras que #if es el tiempo pre-procesador – JaredPar

+0

que es código no válido (probado en VS2008) – JaredPar

+0

De acuerdo. Probado en GCC 4.0.1 en OS X Leopard. –

0

Creo que la definen es _WIN64

13

recomiendo pega el predef SourceForge. No hay una sola respuesta, pero ciertamente puede ayudarlo a comenzar.

EDITAR: Para código solo de GCC, puede usar __i386__ para buscar chips x86 de 32 bits, y sugiero probar __X86_64__ o algo similar para comprobar si hay chips x86 de 64 bits. (Nota: me ha llamado la atención que la respuesta anterior que involucra __ia86__ es en realidad un chip diferente, no un chip x86 de 64 bits. Esto solo muestra mi falta de experiencia en hardware. Para aquellos que tienen más conocimientos de hardware que yo, consumen SourceForge página sobre las macros predefinidas a las que me enlace anteriormente. Es mucho más preciso que yo.) Hay algunas otras que funcionarían, pero esas dos deberían ser bastante universales entre las versiones de GCC.

+0

¿Será __ia64__ cierto para una compilación normal de bits intel64? ¿O hay un __amd64__ o similar? – JaredPar

+0

No tengo experiencia con arquitecturas de 64 bits (o con programación en arquitecturas que no sean de Intel), pero de acuerdo con la página de predef, hay un __amd64__ para AMD de 64 bits. __ia64__ parece ser específico de x86. –

+0

__i386__ solo funcionaría al compilar para intel cpu, ¿correcto? En Solaris compilamos para sparc-s2. – veefu

1

Depende de su sistema operativo y compilador, esas son decisiones de implementación.

0

No existe tal símbolo definido por el estándar C++; su plataforma específica (que no ha especificado en su pregunta) puede proporcionar uno.

2

Lo que probablemente terminaría haciendo, está dentro de un Makefile, determine si está en una plataforma de 32 bits o de 64 bits usando uname. Luego, agregue a sus CFLAGS, -DX32 o -DX64. Que podrías simplemente #ifdef X64.

Pero esto es solo una solución unixy. No estoy seguro de lo que haría en Windows.

+0

El problema es que aunque el sistema que se usa para la compilación es de 64 bits, puede estar compilando un ejecutable de 32 bits. Sin embargo, tiene usted razón en que esta información debe estar expuesta de alguna manera en el archivo MAKE. Al compilador se le debe decir si 32 o 64 están dirigidos. Debería ser capaz de adaptar eso. – veefu

2

Al menos Solaris de 32 bits tiene un límite de 256 apuntadores de archivo porque la estructura almacena el descriptor de archivo en un campo unsigned char. Esto se mantiene por compatibilidad con versiones anteriores de algunas versiones de SunOS casi imposibles. Otras plataformas, estoy tentado de decir que la mayoría de las otras plataformas, no comparten esa limitación. Por otro lado, es relativamente inusual que un programa de usuario común necesite tantos archivos abiertos al mismo tiempo; más a menudo indica un error (no cerrar los archivos cuando termina con ellos) que no. Dicho esto, puede ser un problema para cosas como servidores de bases de datos que necesitan tener muchos archivos de datos abiertos al mismo tiempo.


Un comentario dice:

que es casi la misma. No tenemos una gran cantidad de archivos abiertos, pero el servidor maneja una gran cantidad de conexiones de clientes. Los manejadores de socket y los descriptores de archivos parecen provenir del mismo lugar. Cuando tenemos una gran cantidad de conexiones, 'fopen' falla porque las llamadas a nivel de sistema y vuelve fd> 255.

'Socket mangos' son descriptores de archivos a nivel de llamada al sistema, por lo que vienen del mismo lugar como descripciones de archivos regulares para archivos.

Si tiene que solucionar esto, entonces debe ajustar su código de apertura de socket actual para que si obtiene un descriptor de archivo en el rango 0..255, llame a 'dup2()' para crear un descriptor de archivo en el rango que stdio no usará y luego cierre el descriptor original del archivo. El único problema con esto es que debe hacer un seguimiento de los descriptores de archivos disponibles, ya que dup2 cerrará felizmente el descriptor del archivo de destino si está abierto actualmente.

Por supuesto, supongo que su código de socket lee los descriptores de archivo y no los punteros de archivo. Si ese es el caso, tienes problemas más grandes: demasiadas cosas quieren usar los mismos recursos y no todos pueden usarlos al mismo tiempo.

+0

Eso es casi todo. No tenemos una gran cantidad de archivos abiertos, pero el servidor maneja una gran cantidad de conexiones de clientes. Los manejadores de socket y los descriptores de archivos parecen provenir del mismo lugar. Cuando tenemos muchas conexiones, 'fopen' falla porque la llamada a nivel del sistema retorna y fd> 255. – veefu

+0

+1 para una visión más profunda. – veefu

+0

Sí, eso es casi exactamente lo que he implementado. llamadas envueltas a 'socket' y 'accept' con código que llama a 'fcntl' para duplicar el identificador cuando <255, cierra el original y usa el más alto. Esto funciona bien, pero debe estar aislado de la plataforma que se necesita. De ahí la pregunta sobre #ifdef. – veefu

1

utilizo una construcción como esta para Windows:

 
#if defined(_WIN64) 
    //64-bit code 
#elif defined(_M_IX86) 
    //32-bit code 
#else 
#error "Unknown platform" 
#endif 

Versus:

 
#if defined(_WIN64) 
    // 64 bit code 
#else 
    // 32-bit code 
#endif 

En la primera solución, debido a la #error el compilador será capaz de saber a donde necesita para agregar código para una nueva plataforma. Esto ayuda al mantenimiento en caso de que encuentre una plataforma que no sea de 64 bits ni de 32 bits. Sí, el _M_IX86 no es exactamente sinónimo de 32 bits, pero creo que la única plataforma de 32 bits que la mayoría de nosotros soporta es, de hecho, x86. Entonces, como medida práctica, es suficiente.

En la solución posterior tendrá que averiguar manualmente dónde necesita el código para su nueva plataforma usando grep o algo así. Esto es tedioso y propenso a errores.

Se me ocurre que la siguiente construcción también sería aceptable, aunque no la he probado en producción ni he pensado mucho en ella.

 
#if defined(_WIN64) 
    //64-bit code 
#elif defined(_WIN32) 
    //32-bit code 
#else 
#error "Unknown platform" 
#endif 
Cuestiones relacionadas