Em quais ocasiões devo utilizar um unsigned char ou um char em C? [RESOLVIDO]

1. Em quais ocasiões devo utilizar um unsigned char ou um char em C? [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 23/01/2019 - 16:38h

Recentemente andei lendo um pouco sobre a diferença entre um char e um unsigned char. Consegui entender a diferença básica entre os dois, entretanto, não captei a ideia por traz do uso de um unsigned char, ou melhor, eu praticamente não sei quando é a hora certa de se usar um char ou um unsigned char.

Portanto, venho aqui com a seguinte questão: Em quais ocasiões devo utilizar um unsigned char ou um char em C?



  


2. MELHOR RESPOSTA

Fernando
phoemur

(usa Debian)

Enviado em 23/01/2019 - 20:10h

Complementando a resposta acima:

Um dado do tipo char conseguiria armazenar números inteiros de -127 a +127.
Já um dado do tipo unsigned char conseguiria armazenar números inteiros de 0 a 255.

A tabela ASCII normal vai de 0 a 127, então as duas formas comportariam.
Já a tabela ASCII extendida vai até 255, para comportar caracteres como por exemplo acentuados como á,ê,ç, etc...
Nesse caso apenas unsigned chars dariam para representar adequadamente.

Já se for além disso e necessitar de suporte a Unicode, talvez fosse até o caso de usar um wide char -> wchar_t, que geralmente tem 32 bits - a depender da arquitetetura - para representar adequadamente toda a tabela unicode...
______________________
https://github.com/phoemur

3. Re: Em quais ocasiões devo utilizar um unsigned char ou um char em C? [RESOLVIDO]

-
BiaMonteiro

(usa Arch Linux)

Enviado em 23/01/2019 - 17:36h

Unsigned é um termo usado para definir que o dado usará somente números positivos e o zero.
Um int em 32 bits só é capaz de trabalhar com valores entre -2.147.483.648 e 2.147.483.648. Mas um unsigned int entre 0 e 4,294,967,295.
Caso a arquitetura não seja 32 bits, os intervalos irão mudar, mas sempre haverá intervalo!

A grosso modo, o char é um número. Se você armazenar 65 em uma variável char e pedir para imprimir com printf("%c\n", variavel), seu resultado será a letra "A", que é representada pelo número 65. Isso porque o C trabalha com ASCII, o American Standard Code for Information Interchange (Código Padrão Norte-americado para Intercâmbio de Informações).

Char e unsigned char trabalham praticamente da mesma maneira que int e unsigned int.

Agora no quesito memória, os tipos de dados char e unsigned char alocam a mesma quantidade de bytes.
#include <stdio.h>
#include <stdlib.h>

int main(){
printf("%d\n", sizeof(char));
printf("%d\n", sizeof(unsigned char));

return 0;
}


1
1



4. Re: Em quais ocasiões devo utilizar um unsigned char ou um char em C?

Fernando
phoemur

(usa Debian)

Enviado em 23/01/2019 - 20:15h

Outro uso de unsigned char é para armazenar dados lidos com forma binária, por causa dos seguintes motivos:

In C the unsigned char data type is the only data type that has all the following three properties simultaneously

* it has no padding bits, that it where all storage bits contribute to the value of the data
* no bitwise operation starting from a value of that type, when converted back into that type, can produce overflow, trap representations or undefined behavior
* it may alias other data types without violating the "aliasing rules", that is that access to the same data through a pointer that is typed differently will be guaranteed to see all modifications


Então geralmente quando você usar qualquer biblioteca que envolva a manipulação de dados binários, como por exemplo OpenSSL, você vai ter uma interface que exige o uso de unsigned char pelos motivos acima. Um unsigned char representando um byte

*Ref: http://stackoverflow.com/questions/13642381/c-c-why-to-use-unsigned-char-for-binary-data
______________________
https://github.com/phoemur


5. Re: Em quais ocasiões devo utilizar um unsigned char ou um char em C? [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 23/01/2019 - 21:46h

phoemur escreveu:

A tabela ASCII normal vai de 0 a 127, então as duas formas comportariam.
Já a tabela ASCII extendida vai até 255, para comportar caracteres como por exemplo acentuados como á,ê,ç, etc...
Nesse caso apenas unsigned chars dariam para representar adequadamente.

Já se for além disso e necessitar de suporte a Unicode, talvez fosse até o caso de usar um wide char -> wchar_t, que geralmente tem 32 bits - a depender da arquitetetura - para representar adequadamente toda a tabela unicode...
______________________
https://github.com/phoemur


Era somente disso que precisava saber :)

---> Recentemente andei lendo um pouco sobre a diferença entre um char e um unsigned char. Consegui entender a diferença básica entre os dois, ... <---

De resto já havia entendido usando o duckduckgo :)




6. Re: Em quais ocasiões devo utilizar um unsigned char ou um char em C? [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 23/01/2019 - 23:14h

Você tem, antes de tudo, de lembrar que, embora o nome básico do tipo seja char (abreviação de character, que significa caráter, ou um símbolo que pode ser impresso), em C os tipos char, signed char e unsigned char são tipos numéricos, que aceitam operações aritméticas. O nome do tipo faz referência a caracteres porque, no passado (antes de Unicode e antes de haver preocupações com internacionalização), oito bits eram mais do que suficientes para acomodar os caracteres e sinais de controle dos equipamentos de comunicações então existentes.

Quando o C surgiu, a máquina onde foi primeiramente implementado tinhas duas possíveis representação de inteiros: com oito bits ou com dezesseis. Como um dos usos mais comuns de inteiros de menor capacidade era para representar caracteres, decidiu-se chamar o tipo menor de char e o maior de int, embora ambos possuam todas as propriedades numéricas e aritméticas.

Poder representar números negativos ou não foi uma coisa que surgiu algum tempo depois, e foi aplicada a todos os tipos numéricos integrais, porque muitas aplicações prescindem de números negativos, e podem se beneficiar de usar um bit a mais para contar o dobro de números não-negativos.

Mas, além do tamanho, uma diferença entre char e os outros tipos integrais está justamente na representação do tipo char quando não-explicitamente qualificado com signed ou unsigned. O tipo int, por exemplo, é sempre com sinal, e é um sinônimo exato de “signed int” e apenas “signed”, e o mesmo vale para short, long e long long. Com char, a lógica é outra: cada implementação é livre para decidir se char se comporta de modo semelhante a signed char ou como unsigned char. Nos nossos PCs com Intel, o padrão é ter comportamento de signed char; em arquiteturas ARM ou Sparc, o padrão é se comportar como unsigned char.

Porém, mesmo que uma implementação tenha bem claro qual comportamento usar, o tipo char permanece distinto tanto de unsigned char quanto de unsigned char. Isso não-raramente provoca alguma confusão, sobretudo em duas situações: quando existe promoção de char não-qualificado para int (ou outro tipo numérico de tamanho maior que o de um único char) ou quando se tenta converter implicitamente um ponteiro para uma das três variações em uma das outras duas.

Uma fonte muito comum de erro é quando se usam as funções de <ctype.h>. Essas funções esperam receber um valor inteiro que seja exatamente igual a -1 ou que possa ser ser representado como unsigned char. Então, se c é um valor do tipo char, é ERRADO, produzindo comportamento indefinido (pode funcionar ou não), chamar, por exemplo, “isalpha(c)” ou “toupper(c)”. O certo seria transformar explicitamente o valor proveniente de um char não-qualificado (ou qualificado como signed) em um valor do tipo unsigned char (por exemplo, fazendo uma conversão explícita: “isalpha((unsigned char)c)”) ou trabalhar com unsigned char o tempo todo. Contudo, trabalhar com unsigned char o tempo todo é inconveniente porque outras funções da biblioteca padrão, tais como as de <string.h> e <stdlib.h> usam ponteiros para char não-qualificado, e ponteiros para unsigned char passados como argumentos para essas funções dariam erro de tipo, a não ser que se fizessem também conversões de tipo explícitas.



No dia-a-dia, o mais comum quando se trabalha com texto é usar char não-qualificado para caracteres e arrays de char não-qualificado para strings, a fim de manter compatibilidade com as funções de <string.h>, <stdlib.h> e <stdio.h>, entre outras, e usar as variações qualificadas, com ou sem sinal, para representar números que, respectivamente, possam ou não ser negativos. Mas há exceções: uma delas, já mencionada, é quando se precisa das funções de <ctype.h>, que exigem conversão de valor.


... “Principium sapientiae timor Domini, et scientia sanctorum prudentia.” (Proverbia 9:10)


7. Re: Em quais ocasiões devo utilizar um unsigned char ou um char em C? [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 24/01/2019 - 01:11h

Algumas correções a alguns comentários feitos acima:

Se você armazenar 65 em uma variável char e pedir para imprimir com printf("%c\n", variavel), seu resultado será a letra "A", que é representada pelo número 65. Isso porque o C trabalha com ASCII, o American Standard Code for Information Interchange (Código Padrão Norte-americado para Intercâmbio de Informações).

Não necessariamente. O C não prescreve nenhum conjunto de caracteres. É possível ter C em máquinas que usem EBCDIC (como mainframes da IBM, que até hoje usam esse conjunto de caracteres; nessa máquina, o caráter impresso como resultado do trecho de código acima seria um caráter inválido).

A única relação do C com ASCII é que o padrão evita usar na na definição da linguagem símbolos que não tenham representação no ASCII (como setinhas, usadas em PL/I, ou “¬”, usado em outras e na própria notação de Lógica Matemática). O padrão do C reconhece ainda que nem todos os caracteres do ASCII usados por um programa em C estão presentes em todos os conjuntos de caracteres (por exemplo: “#”, “<”, “>”, “^” ou “~”, entre outros), e oferece meios alternativos, como dígrafos e trígrafos, como substitutos quando se usam tais conjuntos.


Char e unsigned char trabalham praticamente da mesma maneira que int e unsigned int.

De novo, não necessariamente. char pode representar o mesmo conjunto de valores de signed char ou o mesmo conjunto de valores de unsigned char, dependendo do sistema e de como o compilador tenha sido configurado para funcionar. Ainda que o default dos PCs com x86 ou amd64 seja ter caracteres que vão de -128 a 127, isso geralmente pode ser mudado manualmente no momento da compilação por meio de opções do compilador.


printf("%d\n", sizeof(char)); 

Quando o argumento passado para printf (ou recebido através de scanf) é do tipo size_t (que é o caso do valor devolvido pelo operador sizeof), o certo seria dizer o seguinte.
printf("%zu\n", sizeof(char)); 



Um dado do tipo char conseguiria armazenar números inteiros de -127 a +127.

A não ser que a configuração default do compilador (ou aquela solicitada explicitamente por quem vai compilar o programa) faça com que a compilação considere char não-qualificado como sem sinal. Se nos nossos PCs o mais comum é usar com sinal, nos nossos dispositivos Android baseados em ARM é mais comum que seja sem sinal.

E o menor negativo nos nossos PCs com Intel é -128.


Já a tabela ASCII extendida vai até 255

Qual é “a” tabela ASCII estendida (formas verbais com s)? Existem vários conjuntos de caracteres, com diferentes tamanhos, que deliberadamente escolheram colocar nas primeiras 128 posições os mesmos símbolos que o ASCII e na mesma ordem, podendo, por isso, até ser entendidos como extensões (formas nominais com x) do ASCII. Mas nenhum desses conjuntos pode ser considerado, de iure, “a” extensão do padrão — talvez o que mais se aproxime, contendo apenas oito bits, sejam os conjuntos definidos pela ISO-8859; mas, como ficam claro, nem mesmo essa norma define apenas um conjunto, mas vários.


... “Principium sapientiae timor Domini, et scientia sanctorum prudentia.” (Proverbia 9:10)






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts