Qual é o tamanho dos bits longos no Windows de 64 bits?

137

Há pouco tempo, alguém me disse que longnão são 64 bits em máquinas de 64 bits e eu sempre devo usá-lo int. Isso não fazia sentido para mim. Vi documentos (como o site oficial da Apple) dizerem que longsão de fato 64 bits ao compilar para uma CPU de 64 bits. Procurei o que era no Windows de 64 bits e encontrei

  • Janelas: longe intpermanecem 32 bits de comprimento, e novos tipos de dados especiais são definidos para números inteiros de 64 bits.

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

O que devo usar? Devo definir algo como uw, sw((un) largura assinado) como longse não no Windows, e de outra forma fazer uma verificação sobre o Bitsize CPU-alvo?

Csaba
fonte
No Windows com MSVC ++ int e long são 32 bits: msdn.microsoft.com/en-us/library/3b2e7499.aspx . No entanto, para permitir, por exemplo, que os vetores armazenem mais de 4G de itens, size_t é de 64 bits. Portanto, é necessário usar int64_t em vez de int iterar, por exemplo, vetores que podem conter mais de itens 4G.
Serge Rogatch
1
Em Cygwin sizeof(long) == 8, mesmo no Windows :-)
rustyx
@SergeRogatch eles devem usar size_tou um tipo de iterador para iterar, não intouint64_t
phuclv
2
@ LưuVĩnhPhúc, size_ttorna-se complicado perto de números negativos, porque size_tnão está assinado. Então, for(size_t i=0; i<v.size()-2; i++)não para o tamanho do vetor 0 e 1. Outro exemplo: for(size_t i=v.size()-1; i>=0; i--).
Serge Rogatch
2
Se você está fazendo contas com ponteiros (ou seja, com size_tvalores, o resultado deve ser mantido em uma variável do ptrdiff_ttipo - que é projetada para ser grande o suficiente para armazenar esse resultado e é um tipo assinado precisamente por esse motivo!)
SlySven

Respostas:

260

No mundo Unix, havia alguns arranjos possíveis para o tamanho de números inteiros e ponteiros para plataformas de 64 bits. Os dois mais amplamente utilizados foram ILP64 (na verdade, apenas alguns exemplos disso; Cray era um deles) e LP64 (para quase todo o resto). Os acronynms vêm de 'int, long, ponteiros são de 64 bits' e 'longos, ponteiros são 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

O sistema ILP64 foi abandonado em favor do LP64 (ou seja, quase todos os participantes posteriores usaram o LP64, com base nas recomendações do grupo Aspen; somente sistemas com uma longa herança de operação de 64 bits usam um esquema diferente). Todos os sistemas Unix modernos de 64 bits usam LP64. MacOS X e Linux são sistemas modernos de 64 bits.

A Microsoft usa um esquema diferente para fazer a transição para 64 bits: LLP64 ('longo, ponteiros são 64 bits'). Isso tem o mérito de significar que o software de 32 bits pode ser recompilado sem alterações. Ele tem o demérito de ser diferente do que todo mundo faz e também exige que o código seja revisado para explorar as capacidades de 64 bits. Sempre houve revisão necessária; era apenas um conjunto diferente de revisões das necessárias nas plataformas Unix.

Se você projetar seu software em torno de nomes de tipos inteiros neutros em plataforma, provavelmente usando o <inttypes.h>cabeçalho C99 , que, quando os tipos estão disponíveis na plataforma, fornece, assinado (listado) e não assinado (não listado; prefixo com 'u'):

  • int8_t - inteiros de 8 bits
  • int16_t - inteiros de 16 bits
  • int32_t - números inteiros de 32 bits
  • int64_t - números inteiros de 64 bits
  • uintptr_t - números inteiros não assinados grandes o suficiente para conter ponteiros
  • intmax_t- maior tamanho de número inteiro na plataforma (pode ser maior que int64_t)

Em seguida, você pode codificar seu aplicativo usando esses tipos onde for importante e tendo muito cuidado com os tipos de sistema (que podem ser diferentes). Há um intptr_ttipo - um tipo inteiro assinado para conter ponteiros; você deve planejar não usá-lo ou apenas usá-lo como resultado de uma subtração de dois uintptr_tvalores ( ptrdiff_t).

Mas, como a pergunta aponta (em descrença), existem sistemas diferentes para os tamanhos dos tipos de dados inteiros em máquinas de 64 bits. Acostume-se a isso; o mundo não vai mudar.

Jonathan Leffler
fonte
12
Para aqueles que estão no mercado há tempo suficiente, a transição de 64 bits tem alguns paralelos com a transição de 16 para 32 bits de meados dos anos 80. Havia computadores que eram IL32 e outros que eram L32 (adaptando a nova notação ao antigo problema). Às vezes, 'int' era de 16 bits, outras de 32 bits.
Jonathan Leffler
4
Não esqueça que isso se aplica apenas aos idiomas C-ish. Outros têm especificações mais sutis, onde a) o escritor do compilador não pode escolher o tamanho dos tipos de dados nem b) a representação física dos tipos de dados não "vaza" ou c) os números sempre são infinitamente grandes.
Jörg W Mittag
2
Verdadeiro - mas para os idiomas que especificam o comportamento, não há um problema em primeiro lugar. Por exemplo, Java tem um 'longo', mas o tamanho é fixo (64 bits?), Em todas as plataformas. Portanto, não há problemas ao migrar para uma máquina de 64 bits; o tamanho não muda.
Jonathan Leffler
17
@ TomFobear: O ILP64 apresenta uma questão importante - como você chama o tipo de 32 bits? Ou, se você chama o tipo de 32 bits short, como chama o tipo de 16 bits? E se você chama o tipo de 16 bits charpara UTF-16 etc, como chama o tipo de 8 bits? Portanto, o uso do LP64 deixa você com 8 bits char, 16 bits short, 32 bits int, 64 bits long, com espaço para expansão ascendente para 128 bits long longquando (se?) Isso se tornar relevante. Depois disso, você tem mais poderes de 256 do que nomes em C (bem, suponho que você possa ter um de 256 bits intmax_te só então você acaba). Há mérito no LP64.
31416 Jonathan Leffler
2
Talvez isso seja óbvio para vocês, mas acho que vale a pena notar que o C # usa tamanhos inteiros diferentes de todo o resto. Recentemente, fui enganado pela interface com uma DLL, pois o C # usa longos de 64 bits ( msdn.microsoft.com/en-us/library/ms173105.aspx ).
Compholio
57

Não está claro se a pergunta é sobre o compilador Microsoft C ++ ou a API do Windows. No entanto, como não há [c ++], presumo que seja sobre a API do Windows. Algumas das respostas sofreram com a podridão do link, por isso estou fornecendo outro link que pode apodrecer.


Para obter informações sobre os tipos de API do Windows INT, como ,LONG etc. há uma página no MSDN:

Tipos de dados do Windows

As informações também estão disponíveis em vários arquivos de cabeçalho do Windows, como WinDef.h . Listei alguns tipos relevantes aqui:

Tipo | S / U x86 x64
---------------------------- + ----- + -------- + ------ -
BYTE, BOOLEAN | U 8 bits | 8 bit
---------------------------- + ----- + -------- + ------ -
CURTO | S 16 bits | 16 bit
USHORT, PALAVRA | U 16 bits | 16 bit
---------------------------- + ----- + -------- + ------ -
INT, LONGO | S 32 bits | 32 bit
UINT, ULONG, DWORD | U 32 bits | 32 bit
---------------------------- + ----- + -------- + ------ -
INT_PTR, LONG_PTR, LPARAM | S 32 bits | 64 bits
UINT_PTR, ULONG_PTR, WPARAM | U 32 bits | 64 bits
---------------------------- + ----- + -------- + ------ -
LONGLONG S 64 bits | 64 bits
ULONGLONG, QWORD | U 64 bits | 64 bits

A coluna "S / U" indica assinado / não assinado.

Martin Liversage
fonte
4

Este artigo no MSDN faz referência a vários aliases de tipo (disponíveis no Windows) que são um pouco mais explícitos em relação à sua largura:

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

Por exemplo, embora você possa usar o ULONGLONG para fazer referência a um valor integral não assinado de 64 bits, também é possível usar o UINT64. (O mesmo vale para ULONG e UINT32.) Talvez estes sejam um pouco mais claros?

Ruben
fonte
1
Existe alguma garantia de que uint32_t e DWORD serão intercambiáveis? Não é difícil imaginar que eles podem não ser [por exemplo, se o primeiro é de 32 bits inte o último de 32 bits long, o gcc assumiria que um ponteiro para um tipo seria incapaz de usar o apelido do outro, apesar de suas representações correspondentes].
Supercat
4

A Microsoft também definiu UINT_PTR e INT_PTR para números inteiros que são do mesmo tamanho que um ponteiro.

Aqui está uma lista de tipos específicos da Microsoft - faz parte da referência de driver, mas acredito que seja válido também para a programação geral.

Mark Ransom
fonte
2

A maneira mais fácil de conhecê-lo para seu compilador / plataforma:

#include <iostream>

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

A multiplicação por 8 é obter bits dos bytes.

Quando você precisa de um tamanho específico, geralmente é mais fácil usar um dos tipos predefinidos de uma biblioteca. Se isso for indesejável, você pode fazer o que geralmente acontece com o software autoconf e fazer com que o sistema de configuração determine o tipo certo para o tamanho necessário.

Paul de Vrieze
fonte
4
Não que isso importe, mas os bytes de 8 bits não fazem parte da especificação C (cláusula 3.6 e 5.2.4.2.1 do padrão C). Embora seja difícil encontrar uma máquina que não tenha 8 bits, você pode verificar LONG_BIT para ver o tamanho do seu tipo de dados longo.
Andres
Claro, você está certo, na verdade é dependente da arquitetura ("unidade endereçável de armazenamento de dados grande o suficiente para armazenar qualquer membro do conjunto de caracteres básico do ambiente de execução"), mas as arquiteturas mais usadas que são iguais a 8 bits.
Paul de Vrieze
Mas o OP não perguntou sobre seu compilador / plataforma; ele perguntou especificamente sobre o Windows de 64 bits - provavelmente porque ele não tem acesso conveniente a um sistema Windows de 64 bits para testar.
Quuxplusone 02/12
0

O tamanho em bits das longplataformas Windows é de 32 bits (4 bytes).

Você pode verificar isso usando sizeof(long).

BeeOnRope
fonte
-2

Se você precisar usar números inteiros de determinado comprimento, provavelmente deverá usar alguns cabeçalhos independentes da plataforma para ajudá-lo. O Boost é um bom lugar para se olhar.

PolyThinker
fonte