¿Cuál es el tamaño de bit largo en Windows de 64 bits?

137

No hace mucho tiempo, alguien me dijo que longno son 64 bits en máquinas de 64 bits y que siempre debería usar int. Esto no tenía sentido para mí. He visto documentos (como el del sitio oficial de Apple) que dicen que en longrealidad son 64 bits al compilar una CPU de 64 bits. Miré qué era en Windows de 64 bits y encontré

  • Windows: longy intpermanecen de 32 bits de longitud, y se definen nuevos tipos de datos especiales para enteros de 64 bits.

(de http://www.intel.com/cd/ids/developer/asmo-na/eng/197664.htm?page=2 )

¿Qué debo usar? ¿Debo definir algo como uw, sw((sin) ancho firmado) como longsi no en Windows, y de lo contrario hacer una verificación en el tamaño de bits de la CPU de destino?

Csaba
fuente
En Windows con MSVC ++ int y long son de 32 bits: msdn.microsoft.com/en-us/library/3b2e7499.aspx . Sin embargo, para permitir, por ejemplo, que los vectores almacenen más de 4G de elementos, size_t es de 64 bits. Por lo tanto, es necesario usar int64_t en lugar de int para iterar, por ejemplo, vectores que pueden contener más de 4 elementos.
Serge Rogatch
1
En Cygwin sizeof(long) == 8, incluso en Windows :-)
rustyx
@SergeRogatch que deberían usar size_to un tipo de iterador para iterar, no intoint64_t
phuclv
2
@ LưuVĩnhPhúc, con size_testo se vuelve complicado cerca de los números negativos, porque size_tno está firmado. Así for(size_t i=0; i<v.size()-2; i++)falla por tamaño del vector 0 y 1. Otro ejemplo: for(size_t i=v.size()-1; i>=0; i--).
Serge Rogatch
2
Si está haciendo cálculos matemáticos en punteros (es decir, con size_tvalores, entonces el resultado debe mantenerse en una variable de ptrdiff_ttipo, ¡que está diseñado para ser lo suficientemente grande como para contener dicho resultado y es un tipo con signo precisamente por esa razón!)
SlySven

Respuestas:

261

En el mundo de Unix, había algunos arreglos posibles para los tamaños de enteros y punteros para plataformas de 64 bits. Los dos más utilizados fueron ILP64 (en realidad, solo unos pocos ejemplos de esto; Cray fue uno de ellos) y LP64 (para casi todo lo demás). Los acrónimos provienen de 'int, long, los punteros son de 64 bits' y 'long, los punteros son de 64 bits'.

Type           ILP64   LP64   LLP64
char              8      8       8
short            16     16      16
int              64     32      32
long             64     64      32
long long        64     64      64
pointer          64     64      64

El sistema ILP64 se abandonó a favor de LP64 (es decir, casi todos los participantes posteriores usaron LP64, según las recomendaciones del grupo Aspen; solo los sistemas con una larga herencia de operación de 64 bits usan un esquema diferente). Todos los sistemas Unix modernos de 64 bits usan LP64. MacOS X y Linux son sistemas modernos de 64 bits.

Microsoft usa un esquema diferente para la transición a 64 bits: LLP64 ('largo largo, los punteros son de 64 bits'). Esto tiene el mérito de significar que el software de 32 bits se puede volver a compilar sin cambios. Tiene el valor de ser diferente de lo que hacen los demás, y también requiere que se revise el código para explotar las capacidades de 64 bits. Siempre hubo una revisión necesaria; fue solo un conjunto diferente de revisiones de las necesarias en las plataformas Unix.

Si diseña su software alrededor de nombres de tipos enteros neutros en la plataforma, probablemente utilizando el <inttypes.h>encabezado C99 , que, cuando los tipos están disponibles en la plataforma, proporciona, con signo (listado) y sin signo (no listado; prefijo con 'u'):

  • int8_t - enteros de 8 bits
  • int16_t - enteros de 16 bits
  • int32_t - enteros de 32 bits
  • int64_t - enteros de 64 bits
  • uintptr_t - enteros sin signo lo suficientemente grandes como para contener punteros
  • intmax_t- mayor tamaño de entero en la plataforma (puede ser mayor que int64_t)

Luego puede codificar su aplicación utilizando estos tipos donde sea importante y teniendo mucho cuidado con los tipos de sistema (que pueden ser diferentes). Hay un intptr_ttipo: un tipo entero con signo para mantener punteros; debe planear no usarlo, o solo usarlo como resultado de una resta de dos uintptr_tvalores ( ptrdiff_t).

Pero, como señala la pregunta (incrédulo), existen diferentes sistemas para los tamaños de los tipos de datos enteros en máquinas de 64 bits. Acostumbrarse a él; El mundo no va a cambiar.

Jonathan Leffler
fuente
12
Para aquellos de uso que han existido el tiempo suficiente, la transición de 64 bits tiene algunos paralelos con la transición de 16 bits a 32 bits de mediados de los 80. Había computadoras que eran IL32 y otras que eran L32 (adaptando la nueva notación al viejo problema). A veces 'int' era de 16 bits, a veces de 32 bits.
Jonathan Leffler
44
No olvide que esto solo se aplica a los lenguajes C-ish. Otros tienen especificaciones más sensatas donde a) el escritor del compilador no puede elegir el tamaño de los tipos de datos de forma voluntaria ob) la representación física de los tipos de datos no "pierde" o c) los enteros son siempre infinitamente grandes.
Jörg W Mittag
2
Es cierto, pero para aquellos idiomas que especifican el comportamiento, no hay un problema en primer lugar. Por ejemplo, Java tiene un 'largo', pero el tamaño es fijo (¿64 bits?), En todas las plataformas. Por lo tanto, no hay problemas al portar a una máquina de 64 bits; El tamaño no cambia.
Jonathan Leffler
17
@TomFobear: ILP64 presenta un problema importante: ¿cómo se llama el tipo de 32 bits? O, si llama al tipo de 32 bits short, ¿cómo llama al tipo de 16 bits? Y si llama al tipo de 16 bits charpara UTF-16, etc., ¿cómo llama al tipo de 8 bits? Entonces, el uso de LP64 te deja con 8 bits char, 16 bits short, 32 bits int, 64 bits long, con espacio para la expansión hacia arriba a 128 bits long longcuando (si?) Eso se vuelve relevante. Después de eso, tienes más potencias de 256 que nombres en C (bueno, supongo que podrías tener 256 bits intmax_t, y solo entonces te quedas sin). Hay mérito para LP64.
Jonathan Leffler
2
Tal vez esto sea obvio para ustedes, pero creo que vale la pena señalar que C # usa tamaños enteros diferentes de todo lo demás. Recientemente me tropecé con la interfaz de una DLL, ya que C # usa longitudes de 64 bits ( msdn.microsoft.com/en-us/library/ms173105.aspx ).
Compholio
57

No está claro si la pregunta es sobre el compilador de Microsoft C ++ o la API de Windows. Sin embargo, no hay una etiqueta [c ++], así que supongo que se trata de la API de Windows. Algunas de las respuestas han sufrido la rotura del enlace, por lo que estoy proporcionando otro enlace que puede pudrirse.


Para obtener información sobre los tipos de API de Windows como INT, LONGetc. , hay una página en MSDN:

Tipos de datos de Windows

La información también está disponible en varios archivos de encabezado de Windows como WinDef.h. He enumerado algunos tipos relevantes aquí:

Tipo | S / U | x86 | x64
---------------------------- + ----- + -------- + ------ -
BYTE, BOOLEANO | U | 8 bit | 8 bits
---------------------------- + ----- + -------- + ------ -
CORTO | S | 16 bit | 16 bit
USHORT, WORD | U | 16 bit | 16 bit
---------------------------- + ----- + -------- + ------ -
INT, LARGO | S | 32 bit | 32 bit
UINT, ULONG, DWORD | U | 32 bit | 32 bit
---------------------------- + ----- + -------- + ------ -
INT_PTR, LONG_PTR, LPARAM | S | 32 bit | 64 bit
UINT_PTR, ULONG_PTR, WPARAM | U | 32 bit | 64 bit
---------------------------- + ----- + -------- + ------ -
LONGLONG | S | 64 bit | 64 bit
ULONGLONG, QWORD | U | 64 bit | 64 bit

La columna "S / U" denota firmado / sin firmar.

Martin Liversage
fuente
4

Este artículo en MSDN hace referencia a una serie de alias de tipo (disponibles en Windows) que son un poco más explícitos con respecto a su ancho:

http://msdn.microsoft.com/en-us/library/aa505945.aspx

Por ejemplo, aunque puede usar ULONGLONG para hacer referencia a un valor integral sin signo de 64 bits, también puede usar UINT64. (Lo mismo ocurre con ULONG y UINT32.) ¿Quizás estos serán un poco más claros?

Rubén
fuente
1
¿Hay alguna garantía de que uint32_t y DWORD sean intercambiables? No es difícil imaginar que podrían no serlo [por ejemplo, si el primero es de 32 bits inty el segundo de 32 bits long, gcc supondría que un puntero a un tipo no podría alias al otro a pesar de sus representaciones coincidentes].
supercat
4

Microsoft también ha definido UINT_PTR e INT_PTR para enteros que son del mismo tamaño que un puntero.

Aquí hay una lista de tipos específicos de Microsoft : es parte de su referencia de controlador, pero creo que también es válida para la programación general.

Mark Ransom
fuente
2

La forma más fácil de conocerlo para su compilador / plataforma:

#include <iostream>

int main() {
  std::cout << sizeof(long)*8 << std::endl;
}

La multiplicación por 8 es obtener bits de bytes.

Cuando necesita un tamaño particular, a menudo es más fácil usar uno de los tipos predefinidos de una biblioteca. Si eso no es deseable, puede hacer lo que sucede a menudo con el software de autoconf y hacer que el sistema de configuración determine el tipo correcto para el tamaño necesario.

Paul de Vrieze
fuente
44
No es que importe, pero los bytes de 8 bits no son realmente parte de la especificación C (cláusula 3.6 y 5.2.4.2.1 del estándar C). Aunque sería difícil encontrar una máquina que no tuviera 8 bits, puede verificar LONG_BIT para ver qué tan grande es su tipo de datos largo.
Andres
Por supuesto, tiene razón, en realidad depende de la arquitectura ("unidad direccionable de almacenamiento de datos lo suficientemente grande como para contener a cualquier miembro del conjunto de caracteres básicos del entorno de ejecución"), pero las arquitecturas más comúnmente utilizadas equivalen a 8 bits.
Paul de Vrieze
Pero el OP no preguntó por su compilador / plataforma; preguntó específicamente sobre Windows de 64 bits, presumiblemente porque no tiene acceso conveniente a un sistema Windows de 64 bits para probar.
Quuxplusone
0

El tamaño en bits de longen plataformas Windows es de 32 bits (4 bytes).

Puede verificar esto usando sizeof(long).

BeeOnRope
fuente
-2

Si necesita usar enteros de cierta longitud, probablemente debería usar algunos encabezados independientes de la plataforma para ayudarlo. Boost es un buen lugar para mirar.

PolyThinker
fuente