Vejo variáveis definidas com esse tipo, mas não sei de onde elas vêm, nem qual é seu objetivo. Por que não usar int ou unsigned int? (E quanto a outros tipos "semelhantes"? Void_t, etc).
Vejo variáveis definidas com esse tipo, mas não sei de onde elas vêm, nem qual é seu objetivo. Por que não usar int ou unsigned int? (E quanto a outros tipos "semelhantes"? Void_t, etc).
Respostas:
Da Wikipedia
Os arquivos
stdlib.h
estddef.h
header definem um tipo de dados chamadosize_t
1, que é usado para representar o tamanho de um objeto. As funções de biblioteca que aceitam tamanhos esperam que sejam do tiposize_t
e o operador sizeof avalia comosize_t
.O tipo real de
size_t
depende da plataforma; um erro comum é assumir quesize_t
é o mesmo que int não assinado, o que pode levar a erros de programação, 2 especialmente quando as arquiteturas de 64 bits se tornam mais prevalentes.
Desde C99 7.17.1 / 2
Os seguintes tipos e macros são definidos no cabeçalho padrão
stddef.h
<snip>
size_t
que é o tipo inteiro não assinado do resultado do operador sizeof
int
e os unsigned int
tipos são 32 bits, enquanto size_t é 64 bits.
De acordo com size_t, a descrição em pt.cppreference.com size_t
é definida nos seguintes cabeçalhos:
std::size_t
...
Defined in header <cstddef>
Defined in header <cstdio>
Defined in header <cstring>
Defined in header <ctime>
Defined in header <cwchar>
size_t
é o tipo inteiro não assinado do resultado do operador sizeof (ISO C99, seção 7.17.)
O sizeof
operador gera o tamanho (em bytes) de seu operando, que pode ser uma expressão ou o nome entre parênteses de um tipo. O tamanho é determinado a partir do tipo do operando. O resultado é um número inteiro. O valor do resultado é definido pela implementação e seu tipo (um tipo inteiro não assinado) é size_t
(ISO C99, Seção 6.5.3.4).
Na prática, size_t
representa o número de bytes que você pode endereçar. Nas arquiteturas mais modernas dos últimos 10 a 15 anos, foram 32 bits, o que também tem o tamanho de um int não assinado. No entanto, estamos migrando para o endereçamento de 64 bits, enquanto o uint
mais provável é permanecer em 32 bits (seu tamanho não é garantido no padrão c ++). Para tornar seu código que depende do tamanho da memória portátil entre arquiteturas, você deve usar a size_t
. Por exemplo, coisas como tamanhos de matriz sempre devem usar size_t
's. Se você observar os contêineres padrão, ::size()
sempre retornará a size_t
.
Observe também que o visual studio possui uma opção de compilação que pode verificar esses tipos de erros chamados "Detectar problemas de portabilidade de 64 bits".
Dessa forma, você sempre sabe qual é o tamanho, porque um tipo específico é dedicado aos tamanhos. A própria pergunta mostra que pode ser um problema: é um int
ou um unsigned int
? Além disso, qual é a magnitude ( short
, int
, long
, etc.)?
Como existe um tipo específico atribuído, você não precisa se preocupar com o comprimento ou a assinatura.
A definição real pode ser encontrada na Biblioteca de Referência C ++ , que diz:
Tipo:
size_t
(tipo integral não assinado)Cabeçalho:
<cstring>
size_t
corresponde ao tipo de dados integral retornado pelo operador de idiomasizeof
e é definido no<cstring>
arquivo de cabeçalho (entre outros) como um tipo integral não assinado.Em
<cstring>
, é usado como o tipo do parâmetronum
nas funçõesmemchr
,memcmp
,memcpy
,memmove
,memset
,strncat
,strncmp
,strncpy
estrxfrm
, que, em todos os casos, é usado para especificar o número máximo de bytes ou caracteres a função tem que afectar.Ele também é usado como o tipo de retorno para
strcspn
,strlen
,strspn
estrxfrm
para tamanhos de retorno e comprimentos.
size_t deve ser definido nos cabeçalhos da sua biblioteca padrão. Na minha experiência, geralmente é simplesmente um typedef para unsigned int. O ponto, porém, é que não precisa ser. Tipos como size_t permitem ao fornecedor da biblioteca padrão a liberdade de alterar seus tipos de dados subjacentes, se apropriado para a plataforma. Se você assumir que size_t é sempre sem assinatura int (por meio de vazamento, etc), poderá ter problemas no futuro se o seu fornecedor alterar size_t para, por exemplo, um tipo de 64 bits. É perigoso assumir algo sobre esse ou qualquer outro tipo de biblioteca por esse motivo.
Não estou familiarizado, void_t
exceto como resultado de uma pesquisa no Google (é usada em uma vmalloc
biblioteca por Kiem-Phong Vo na AT&T Research - tenho certeza de que também é usada em outras bibliotecas).
Os vários xxx_t typedefs são usados para abstrair um tipo de uma implementação definida específica, pois os tipos concretos usados para certas coisas podem diferir de uma plataforma para outra. Por exemplo:
Void_t
abstrai o tipo de ponteiro retornado pelas vmalloc
rotinas da biblioteca porque foi gravado para funcionar em sistemas anteriores à ANSI / ISO C, em que ovoid
palavra chave pode não existir. Pelo menos é o que eu acho.wchar_t
abstrai o tipo usado para caracteres largos, já que em alguns sistemas será do tipo 16 bits, em outros será de 32 bits.Portanto, se você escrever seu código de manipulação de caracteres amplo para usar o wchar_t
tipo em vez de, digamos unsigned short
, esse código provavelmente será mais portátil para várias plataformas.
Em programas minimalistas em que uma size_t
definição não foi carregada "por acaso" em algumas inclusões, mas eu ainda a necessito em algum contexto (por exemplo, para acessar std::vector<double>
), então uso esse contexto para extrair o tipo correto. Por exemplotypedef std::vector<double>::size_type size_t
.
(Coloque, namespace {...}
se necessário, para tornar o escopo limitado.)
Quanto a "Por que não usar int ou unsigned int?", Simplesmente porque é semanticamente mais significativo não usar. Existe a razão prática de que ele pode ser, digamos, typedef
d como int
e depois atualizado para um long
posterior, sem que ninguém precise alterar seu código, é claro, mas mais fundamentalmente do que um tipo deve ser significativo. Para simplificar bastante, uma variável do tipo size_t
é adequada e usada para conter os tamanhos das coisas, assim como time_t
é adequada para conter valores temporais. Como elas são realmente implementadas deve ser o trabalho da implementação. Comparado a apenas chamar tudo int
, o uso de nomes de tipos significativos como esse ajuda a esclarecer o significado e a intenção do seu programa, assim como qualquer tipo rico de tipos.