Qual é a vantagem de usar uint8_t
mais unsigned char
em C?
Eu sei que em quase todos os sistemas uint8_t
é apenas um typedef unsigned char
, então por que usá-lo?
Qual é a vantagem de usar uint8_t
mais unsigned char
em C?
Eu sei que em quase todos os sistemas uint8_t
é apenas um typedef unsigned char
, então por que usá-lo?
Respostas:
Ele documenta sua intenção - você armazenará pequenos números, em vez de um personagem.
Também parece melhor se você estiver usando outros typedefs como uint16_t
ou int32_t
.
unsigned char
ou signed char
documentar explicitamente a intenção também, uma vez que sem adornos char
é o que mostra que você está trabalhando com personagens.
unsigned
era unsigned int
por definição?
char
parece implicar um caractere, enquanto que no contexto de uma string UTF8, pode ser apenas um byte de um caractere multibyte. O uso de uint8_t pode deixar claro que não se deve esperar um caractere em todas as posições - em outras palavras, que cada elemento da string / array é um número inteiro arbitrário sobre o qual não se deve fazer suposições semânticas. É claro que todos os programadores C sabem disso, mas pode ser necessário que os iniciantes façam as perguntas certas.
Apenas para ser pedante, alguns sistemas podem não ter um tipo de 8 bits. De acordo com a Wikipedia :
É necessária uma implementação para definir tipos inteiros de largura exata para N = 8, 16, 32 ou 64 se e somente se tiver algum tipo que atenda aos requisitos. Não é necessário defini-los para nenhum outro N, mesmo que ele suporte os tipos apropriados.
Portanto, uint8_t
não existe garantia de existência, embora exista para todas as plataformas em que 8 bits = 1 byte. Algumas plataformas incorporadas podem ser diferentes, mas isso está ficando muito raro. Alguns sistemas podem definir char
tipos como 16 bits; nesse caso, provavelmente não haverá um tipo de 8 bits de qualquer tipo.
Fora essa questão (menor), a resposta de @Mark Ransom é a melhor na minha opinião. Use o que mostra mais claramente para o que você está usando os dados.
Além disso, suponho que você quis dizer uint8_t
(o typedef padrão do C99 fornecido no stdint.h
cabeçalho) e não uint_8
(não faz parte de nenhum padrão).
uint8_t
(ou digitar para isso). Isso ocorre porque o tipo de 8 bits teria bits não utilizados na representação de armazenamento, o que uint8_t
não deve ter.
typedef unsigned integer type uint8_t; // optional
Portanto, em essência, uma biblioteca em conformidade com o padrão C ++ não é necessária para definir o uint8_t (consulte o comentário // opcional )
O ponto principal é escrever código independente de implementação. unsigned char
não é garantido que seja do tipo 8 bits. uint8_t
é (se disponível).
sizeof(unsigned char)
retornará 1
por 1 byte. mas se um char int sistema e são do mesmo tamanho de, por exemplo, 16 bits, então sizeof(int)
irá também retornar1
Como você disse, " quase todos os sistemas".
char
provavelmente é um dos menos propensos a mudar, mas assim que você começar a usar os uint16_t
amigos, o uint8_t
melhor será usar as combinações e até fazer parte de um padrão de codificação.
Na minha experiência, existem dois lugares em que queremos usar uint8_t para significar 8 bits (e uint16_t, etc) e onde podemos ter campos menores que 8 bits. Ambos os locais são onde o espaço é importante e, muitas vezes, precisamos examinar um despejo bruto dos dados durante a depuração e precisamos determinar rapidamente o que eles representam.
O primeiro está nos protocolos de RF, especialmente em sistemas de banda estreita. Nesse ambiente, talvez seja necessário agrupar o máximo de informações possível em uma única mensagem. O segundo é no armazenamento flash, onde podemos ter espaço muito limitado (como em sistemas embarcados). Nos dois casos, podemos usar uma estrutura de dados compactada na qual o compilador cuidará da embalagem e descompactação para nós:
#pragma pack(1)
typedef struct {
uint8_t flag1:1;
uint8_t flag2:1;
padding1 reserved:6; /* not necessary but makes this struct more readable */
uint32_t sequence_no;
uint8_t data[8];
uint32_t crc32;
} s_mypacket __attribute__((packed));
#pragma pack()
Qual método você usa depende do seu compilador. Você também pode precisar oferecer suporte a vários compiladores diferentes com os mesmos arquivos de cabeçalho. Isso acontece em sistemas incorporados nos quais dispositivos e servidores podem ser completamente diferentes - por exemplo, você pode ter um dispositivo ARM que se comunica com um servidor Linux x86.
Existem algumas ressalvas no uso de estruturas compactadas. O maior problema é que você deve evitar a exclusão do endereço de um membro. Em sistemas com palavras alinhadas por mutibytes, isso pode resultar em uma exceção desalinhada - e em um coredump.
Algumas pessoas também se preocupam com o desempenho e argumentam que o uso dessas estruturas compactadas tornará o sistema mais lento. É verdade que, nos bastidores, o compilador adiciona código para acessar os membros de dados não alinhados. Você pode ver isso observando o código de montagem no seu IDE.
Porém, como as estruturas compactadas são mais úteis para comunicação e armazenamento de dados, os dados podem ser extraídos para uma representação não compactada ao trabalhar com eles na memória. Normalmente, não precisamos trabalhar com todo o pacote de dados na memória.
Aqui está uma discussão relevante:
pacote pragma (1) nem __attribute__ ((alinhado (1))) funciona
O __attribute __ ((empacotado)) / #pragma do gcc não é seguro?
http://solidsmoke.blogspot.ca/2010/07/woes-of-structure-packing-pragma-pack.html
Há pouco. Do ponto de vista da portabilidade, char
não pode ser menor que 8 bits e nada pode ser menor que char
, portanto, se uma determinada implementação C tiver um tipo inteiro de 8 bits não assinado, será char
. Como alternativa, ele pode não ter um, nesse ponto qualquer typedef
truque é discutível.
Poderia ser usado para documentar melhor seu código, no sentido de que é claro que você precisa de bytes de 8 bits e nada mais. Mas, na prática, já é uma expectativa razoável em praticamente qualquer lugar (existem plataformas DSP nas quais isso não é verdade, mas as chances de seu código ser executado lá são reduzidas e você também pode errar usando uma declaração estática na parte superior do programa em tal plataforma).
unsigned char
que seja possível manter valores entre 0 e 255. Se você puder fazer isso em 4 bits, meu chapéu está para você.
uint8_t
à implementação. Gostaria de saber, compiladores para DSPs com caracteres de 16 bits normalmente implementam uint8_t
, ou não?
#include <stdint.h>
e usar uint8_t
. Se a plataforma possuir, ela será entregue a você. Se a plataforma não a possuir, seu programa não será compilado e o motivo será claro e direto.
Isso é realmente importante, por exemplo, quando você está escrevendo um analisador de rede. os cabeçalhos de pacotes são definidos pela especificação do protocolo, não pela maneira como o compilador C de uma determinada plataforma funciona.
Em quase todos os sistemas, encontrei uint8_t == char não assinado, mas isso não é garantido pelo padrão C. Se você está tentando escrever um código portátil e importa exatamente qual o tamanho da memória, use uint8_t. Caso contrário, use char não assinado.
uint8_t
sempre corresponde ao intervalo, tamanho unsigned char
e preenchimento (nenhum) quando unsigned char
é de 8 bits. Quando unsigned char
não é de 8 bits, uint8_t
não existe.
unsigned char
é de 8 bits, é uint8_t
garantida a ser um typedef
dos mesmos e não uma typedef
de um tipo inteiro não assinado prolongado ?
unsigned char/signed char/char
o menor tipo - não inferior a 8 bits. unsigned char
não tem preenchimento. Para uint8_t
ser, ele deve ter 8 bits, sem preenchimento, devido a um tipo inteiro fornecido pela implementação: correspondendo aos requisitos mínimos de unsigned char
. Quanto a "... garantido ser um typedef ...", parece uma boa pergunta para postar.