O valor máximo de size_t (SIZE_MAX) é definido em relação aos outros tipos de número inteiro?
Estou escrevendo uma biblioteca de funções que irá converter com segurança entre vários tipos numéricos ou morrer tentando. Minha intenção é aproximadamente partes iguais criarem biblioteca-útil e aprender-C-edge-cases.
Minhasint
-para-size_t
função está acionando um GCC-Wtype-limits
aviso que afirma que não devo testar se umint
é melhor queSIZE_MAX
, porque nunca será verdade. (Outra função que converteint
parassize_t
produz um aviso idêntico sobreSSIZE_MAX
.)
Meu MCVE, com comentários extras e etapas do bebê, é:
#include <stdint.h> /* SIZE_MAX */
#include <stdlib.h> /* exit EXIT_FAILURE size_t */
extern size_t i2st(int value) {
if (value < 0) {
exit(EXIT_FAILURE);
}
// Safe to cast --- not too small.
unsigned int const u_value = (unsigned int) value;
if (u_value > SIZE_MAX) { /* Line 10 */
exit(EXIT_FAILURE);
}
// Safe to cast --- not too big.
return (size_t) u_value;
}
Os avisos do compiladorEstou recebendo avisos semelhantes do GCC 4.4.5 no Linux 2.6.34:
$ gcc -std=c99 -pedantic -Wall -Wextra -c -o math_utils.o math_utils.c
math_utils.c: In function ‘i2st’:
math_utils.c:10: warning: comparison is always false due to limited range of data type
... e também do GCC 4.8.5 no Linux 3.10.0:
math_utils.c: In function ‘i2st’:
math_utils.c:10:5: warning: comparison is always false due to limited range of data type [-Wtype-limits]
if (u_value > SIZE_MAX) { /* Line 10 */
^
Esses avisos não parecem justificados para mim, pelo menos não no caso geral. (Não nego que a comparação possa ser "sempre falsa" em uma combinação específica de hardware e compilador.)
Padrão CO padrão C 1999 não parece excluir umaint
sendo maior queSIZE_MAX
.
Seção "6.5.3.4.sizeof
operador "não abordasize_t
, exceto para descrevê-lo como "definido em<stddef.h>
(e outros cabeçalhos) ".
Seção "7.17 Definições comuns<stddef.h>
"definesize_t
como "o tipo inteiro não assinado do resultado dosizeof
operador ". (Obrigado pessoal!)
A seção "7.18.3 Limites de outros tipos inteiros" é mais útil - define "limite desize_t
" Como:
SIZE_MAX
65535
...significadoSIZE_MAX
poderia ser tãopequeno 65535. Umint
(assinado ou não) pode ser muito maior que isso, dependendo do hardware e do compilador.
A resposta aceita para "unsigned int
vs.size_t
"parece apoiar minha interpretação (ênfase adicionada):
osize_t
O tipo pode ser maior que, igual a,ou menor que aunsigned int
, e seu compilador pode fazer suposições sobre isso para otimização.
Esta resposta cita a mesma "Seção 7.17" do padrão C que eu já citei.
Outros documentosMinhas pesquisas exibiram o artigo do Open Group "Neutralidade do tamanho dos dados e suporte a 64 bits", que afirma em" Modelos de dados de 64 bits "(ênfase adicionada):
ISO / IEC 9899: 1990, Linguagens de Programação - C (ISO C) deixaram a definição deshort int
, aint
, along int
, e aspointer
deliberadamente vagas [...] As únicas restrições foram queint
s não deve ser menor queshort
areialong
s não deve ser menor queint
areiasize_t
deve representar o maior tipo não assinado suportado por uma implementação. [...] A relação entre os tipos de dados fundamentais pode ser expressa como:
sizeof(char)
<=sizeof(short)
<=sizeof(int)
<=sizeof(long)
= sizeof(size_t)
Se isso for verdade, teste umint
contraSIZE_MAX
é realmente fútil ... mas este artigo não cita capítulos e versos, então não sei dizer como seus autores chegaram à sua conclusão. Sua própria "Base Specification Version 7"sys/types.h
docs não lide com isso de qualquer maneira.
Eu entendi aquilosize_t
é improvável que seja mais estreito que umint
, maso padrão C garante que comparandosome_unsigned_int > SIZE_MAX
vaisempre ser falso? Se sim, onde?
Existem duas semi-duplicatas dessa pergunta, mas ambas estão fazendo perguntas mais gerais sobre o quesize_t
deve representar e quando não deve / deve ser usado.
"O que ésize_t
em C?"não aborda a relação entresize_t
e os outros tipos inteiros. Sua resposta aceita é apenas uma citação da Wikipedia, que não fornece nenhuma informação além do que eu já encontrei.
"Qual é a definição correta desize_t
?"começa quase uma duplicata da minha pergunta, mas depois desvia o curso, perguntando quandosize_t
deve ser usado e por que foi introduzido. Foi encerrado como uma duplicata da pergunta anterior.