Em vários exemplos de C ++, vejo um uso do tipo em size_t
que eu teria usado um simples int
. Qual a diferença e por que size_t
deveria ser melhor?
Em vários exemplos de C ++, vejo um uso do tipo em size_t
que eu teria usado um simples int
. Qual a diferença e por que size_t
deveria ser melhor?
Respostas:
Da amigável Wikipedia :
Os arquivos de cabeçalho stdlib.he stddef.h definem um tipo de dados chamado size_t que é usado para representar o tamanho de um objeto. As funções de biblioteca que usam tamanhos esperam que sejam do tipo size_t, e o operador sizeof é avaliado como size_t.
O tipo real de size_t depende da plataforma; um erro comum é assumir que size_t é o mesmo que int não assinado, o que pode levar a erros de programação, principalmente quando as arquiteturas de 64 bits se tornam mais prevalentes.
Além disso, verifique Por que o size_t é importante
/usr/include/stdlib.h
obtém a definição /usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stddef.h
e nela é padronizado, a long unsigned int
menos que outro arquivo de cabeçalho diga o contrário.
size_t é o tipo usado para representar tamanhos (como o próprio nome indica). Sua plataforma (e até potencialmente implementação) depende e deve ser usada apenas para esse fim. Obviamente, representando um tamanho, size_t não está assinado. Muitas funções stdlib, incluindo malloc, sizeof e várias funções de operação de string, usam size_t como um tipo de dados.
Um int é assinado por padrão e, embora seu tamanho também seja dependente da plataforma, ele terá 32 bits fixos na maioria das máquinas modernas (e embora size_t seja de 64 bits na arquitetura de 64 bits, o int permanece 32 bits nessas arquiteturas).
Para resumir: use size_t para representar o tamanho de um objeto e int (ou long) em outros casos.
O size_t
tipo é definido como o tipo integral não assinado do sizeof
operador. No mundo real, você verá int
definido como 32 bits (para compatibilidade com versões anteriores), mas size_t
definido como 64 bits (para poder declarar matrizes e estruturas com mais de 4 GiB de tamanho) em plataformas de 64 bits. Se a long int
também tiver 64 bits, isso é chamado de convenção LP64; se long int
tiver 32 bits, long long int
e os ponteiros tiverem 64 bits, é LLP64. Você também pode obter o inverso, um programa que usa instruções de 64 bits para velocidade, mas ponteiros de 32 bits para economizar memória. Além disso, int
está assinado e size_t
não está assinado.
Historicamente, havia várias outras plataformas em que os endereços eram maiores ou menores que o tamanho nativo de int
. De fato, nos anos 70 e início dos anos 80, isso era mais comum do que não: todos os microcomputadores populares de 8 bits tinham registradores e endereços de 16 bits e a transição entre 16 e 32 bits também produziu muitas máquinas que tinham endereços mais amplos que seus registros. Ocasionalmente, ainda vejo perguntas aqui sobre o Borland Turbo C para MS-DOS, cujo modo de memória Enorme tinha endereços de 20 bits armazenados em 32 bits em uma CPU de 16 bits (mas que suportava o conjunto de instruções de 32 bits do 80386); o Motorola 68000 tinha uma ALU de 16 bits com registros e endereços de 32 bits; havia mainframes da IBM com endereços de 15, 24 ou 31 bits. Você também vê diferentes tamanhos de ALU e de barramento de endereços em sistemas incorporados.
Quando o tempo int
é menor size_t
e você tenta armazenar o tamanho ou deslocamento de um arquivo ou objeto muito grande em um unsigned int
, existe a possibilidade de que ele possa estourar e causar um bug. Com um int
, há também a possibilidade de obter um número negativo. Se um int
ou unsigned int
for maior, o programa será executado corretamente, mas desperdiçará memória.
Geralmente, você deve usar o tipo correto para esse fim, se quiser portabilidade. Muitas pessoas recomendam que você use matemática assinada em vez de não assinada (para evitar erros sutis e desagradáveis 1U < -3
). Para o efeito, os define biblioteca padrão ptrdiff_t
em <stddef.h>
como o tipo assinada do resultado da subtração um ponteiro de outro.
Dito isso, uma solução alternativa pode ser verificar os limites de todos os endereços e compensações contra INT_MAX
e / 0
ou INT_MIN
conforme apropriado e ativar os avisos do compilador sobre a comparação de quantidades assinadas e não assinadas, caso você perca alguma. Você deve sempre, sempre, sempre verificar os acessos de sua matriz quanto a estouro em C de qualquer maneira.
É porque size_t pode ser outra coisa senão um int (talvez uma estrutura). A idéia é que desacopla seu trabalho do tipo subjacente.
size_t
é especificado como um tipo inteiro não assinado . C11 §6.5.3.4 5 "O valor do resultado de ambos os operadores ( sizeof
_Alignof
) é definido pela implementação e seu tipo (um tipo inteiro não assinado) é size_t
".
A definição de SIZE_T
é encontrada em:
https://msdn.microsoft.com/en-us/library/cc441980.aspx e https://msdn.microsoft.com/en-us/library/cc230394.aspx
Colando aqui as informações necessárias:
SIZE_T
é um ULONG_PTR
número máximo de bytes para o qual um ponteiro pode apontar.
Este tipo é declarado da seguinte maneira:
typedef ULONG_PTR SIZE_T;
A ULONG_PTR
é um tipo longo não assinado usado para precisão do ponteiro. É usado ao converter um ponteiro para um tipo longo para executar a aritmética do ponteiro.
Este tipo é declarado da seguinte maneira:
typedef unsigned __int3264 ULONG_PTR;
SIZE_T
não é size_t
, o que o OP perguntou.
SIZE_T
é totalmente diferente de size_t
. Você não pode declarar uma variável do tipo SIZE_T
.