Respostas:
O size_t
tipo é o tipo inteiro não assinado que é o resultado do sizeof
operador (e do offsetof
operador); portanto, é garantido que seja grande o suficiente para conter o tamanho do maior objeto que seu sistema pode manipular (por exemplo, uma matriz estática de 8 GB).
O size_t
tipo pode ser maior que, igual a ou menor que um unsigned int
, e seu compilador pode fazer suposições sobre isso para otimização.
Você pode encontrar informações mais precisas no padrão C99, seção 7.17, cujo rascunho está disponível na Internet em formato pdf , ou no padrão C11, seção 7.19, também disponível como rascunho em pdf .
size_t
podem representar! Se não, quem faz?
O clássico C (o dialeto inicial de C descrito por Brian Kernighan e Dennis Ritchie em The C Programming Language, Prentice-Hall, 1978) não forneceu size_t
. O comitê de padrões C apresentado size_t
para eliminar um problema de portabilidade
Explicado em detalhes no site incorporado.com (com um exemplo muito bom)
Em resumo, size_t
nunca é negativo e maximiza o desempenho porque é typedef para ser o tipo inteiro não assinado que é grande o suficiente - mas não muito grande - para representar o tamanho do maior objeto possível na plataforma de destino.
Os tamanhos nunca devem ser negativos e, de fato, size_t
são do tipo não assinado. Além disso, como size_t
não é assinado, é possível armazenar números aproximadamente duas vezes maiores que o tipo assinado correspondente, porque podemos usar o bit de sinal para representar a magnitude, como todos os outros bits do número inteiro não assinado. Quando ganhamos mais um bit, multiplicamos o intervalo de números que podemos representar por um fator de cerca de dois.
Então, você pergunta, por que não usar apenas um unsigned int
? Pode não ser capaz de armazenar números grandes o suficiente. Em uma implementação com unsigned int
32 bits, o maior número que pode representar é 4294967295
. Alguns processadores, como o IP16L32, podem copiar objetos maiores que 4294967295
bytes.
Então, você pergunta, por que não usar um unsigned long int
? Exige um pedágio de desempenho em algumas plataformas. O padrão C exige que um long
ocupe pelo menos 32 bits. Uma plataforma IP16L32 implementa cada comprimento de 32 bits como um par de palavras de 16 bits. Quase todos os operadores de 32 bits nessas plataformas exigem duas instruções, se não mais, porque trabalham com os 32 bits em dois pedaços de 16 bits. Por exemplo, mover um comprimento de 32 bits geralmente requer duas instruções da máquina - uma para mover cada pedaço de 16 bits.
O uso size_t
evita esse custo de desempenho. De acordo com este artigo fantástico , "Type size_t
é um typedef que é um apelido para algum tipo de número inteiro não assinado, normalmente unsigned int
ou unsigned long
, mas possivelmente até unsigned long long
. Cada implementação do Standard C deve escolher o número inteiro não assinado que é grande o suficiente - mas não maior que o necessário - para representar o tamanho do maior objeto possível na plataforma de destino ".
unsigned int
lata e varia de um sistema para outro. É necessário que seja pelo menos 65536
, mas é comum 4294967295
e pode ser 18446744073709551615
(2 ** 64-1) em alguns sistemas.
unsigned char
). O padrão parece não conter a string '65535' ou '65536' em qualquer lugar e '+32767' ocorre apenas (1,9: 9) em uma nota como o maior número possível de números inteiro representável int
; nenhuma garantia é dada, mesmo que INT_MAX
não possa ser menor que isso!
O tipo size_t é o tipo retornado pelo operador sizeof. É um número inteiro não assinado capaz de expressar o tamanho em bytes de qualquer intervalo de memória suportado na máquina host. É (normalmente) relacionado a ptrdiff_t, em que ptrdiff_t é um valor inteiro assinado, de modo que sizeof (ptrdiff_t) e sizeof (size_t) sejam iguais.
Ao escrever o código C, você sempre deve usar size_t sempre que lidar com intervalos de memória.
O tipo int, por outro lado, é basicamente definido como o tamanho do valor inteiro (assinado) que a máquina host pode usar para executar com eficiência a aritmética inteira. Por exemplo, em muitos computadores mais antigos do tipo PC, o valor sizeof (size_t) seria 4 (bytes), mas sizeof (int) seria 2 (byte). A aritmética de 16 bits era mais rápida que a aritmética de 32 bits, embora a CPU pudesse lidar com um espaço de memória (lógico) de até 4 GiB.
Use o tipo int somente quando você se preocupa com a eficiência, pois sua precisão real depende muito das opções do compilador e da arquitetura da máquina. Em particular, o padrão C especifica os seguintes invariantes: sizeof (char) <= sizeof (short) <= sizeof (int) <= sizeof (long) não colocando outras limitações na representação real da precisão disponível ao programador para cada um dos esses tipos primitivos.
Nota: NÃO é o mesmo que em Java (que realmente especifica a precisão de bits para cada um dos tipos 'char', 'byte', 'short', 'int' e 'long').
size_t
é capaz de representar o tamanho de qualquer objeto único (por exemplo: número, matriz, estrutura). Todo o intervalo de memória pode excedersize_t
size_t
- espero que você não esteja falando sério. Na maioria das vezes, não lidamos com matrizes em que a cardinalidade do espaço de endereço + portabilidade é importante. Nesses casos, você aceitaria size_t
. Nos demais casos, você obtém índices de números inteiros (assinados). Como a confusão (que ocorre sem aviso prévio) decorrente do comportamento inesperado de sub-fluxo de assinaturas é mais comum e pior que os problemas de portabilidade que podem surgir nos outros casos.
Digite size_t deve ser grande o suficiente para armazenar o tamanho de qualquer objeto possível. Int não assinado não precisa atender a essa condição.
Por exemplo, nos sistemas de 64 bits, int e unsigned int podem ter 32 bits de largura, mas size_t deve ser grande o suficiente para armazenar números maiores que 4G
size_t
que só teria que ser tão grande se o compilador pudesse aceitar um tipo X tal que sizeof (X) renderia um valor maior que 4G. A maioria dos compiladores rejeitaria typedef unsigned char foo[1000000000000LL][1000000000000LL]
, por exemplo , e foo[65536][65536];
poderia mesmo ser legitimamente rejeitada se excedesse um limite definido pela implementação documentado.
Este trecho do manual glibc 0.02 também pode ser relevante ao pesquisar o tópico:
Há um problema em potencial com o tipo size_t e as versões do GCC anteriores à liberação 2.4. O ANSI C exige que size_t sempre seja um tipo não assinado. Para compatibilidade com os arquivos de cabeçalho dos sistemas existentes, o GCC define size_t em stddef.h' to be whatever type the system's
sys / types.h 'como ele é. A maioria dos sistemas Unix que definem size_t em `sys / types.h ', definem como um tipo assinado. Algum código na biblioteca depende do tamanho_t ser um tipo não assinado e não funcionará corretamente se estiver assinado.
O código da biblioteca GNU C que espera que size_t não seja assinado está correto. A definição de size_t como um tipo assinado está incorreta. Planejamos que na versão 2.4, o GCC sempre defina size_t como um tipo não assinado e o fixincludes' script will massage the system's
sys / types.h 'para não entrar em conflito com isso.
Enquanto isso, resolvemos esse problema dizendo ao GCC explicitamente para usar um tipo não assinado para size_t ao compilar a biblioteca GNU C. O `configure 'detectará automaticamente o tipo que o GCC usa para size_t organizar para substituí-lo, se necessário.
Se meu compilador estiver definido como 32 bits, size_t
não será outro senão um typedef para unsigned int
. Se meu compilador estiver definido como 64 bits, size_t
nada mais será do que um typedef para unsigned long long
.
unsigned long
para os dois casos em alguns sistemas operacionais.
size_t é o tamanho de um ponteiro.
Portanto, em 32 bits ou no modelo comum ILP32 (inteiro, longo, ponteiro) size_t é 32 bits. e em 64 bits ou no modelo LP64 (longo, ponteiro) comum size_t é de 64 bits (números inteiros ainda são 32 bits).
Existem outros modelos, mas esses são os que o g ++ usa (pelo menos por padrão)
size_t
não é necessariamente do mesmo tamanho que um ponteiro, embora geralmente seja. Um ponteiro deve ser capaz de apontar para qualquer local na memória; size_t
só precisa ser grande o suficiente para representar o tamanho do maior objeto único.