Binario negativo

1. Binario negativo

MARCOS
gellox

(usa Outra)

Enviado em 24/01/2013 - 13:40h

Pessoal imaignem a seguinte situação:

Possuo um arquivo binário que o seu conteúdo em 1(um) determinado byte ao converter para decimal deveria ser -10.
Eu consigo ler todos os bytes positivos, porém quando o valor e negativo ele não me retorna o valor exato.
Já li muito e ouvir falar algo sobre complemento de 2 (dois) e/ou sinal de magnitude.

Alguém poderia me ajudar ??

Obrigado



  


2. Re: Binario negativo

Paulo
paulo1205

(usa Ubuntu)

Enviado em 24/01/2013 - 14:10h

Seria bom você mostrar seu código de leitura desses bytes. A causa mais provável de problemas é você estar lendo de forma ou com tipos de dados diferentes de como os dados foram gravados.


3. Re: Binario negativo

MARCOS
gellox

(usa Outra)

Enviado em 24/01/2013 - 14:25h

gellox escreveu:

Segue o código lendo apenas 1 byte.

int a;
FILE *arq;

int main()
{
arq = fopen("arquivo.bin", "rb");
if (arq==NULL)
{
printf("Erro ao abrir arquivo!!!\n");
system("pause");
exit(1);
}
a=fgetc(arq);
if (a==EOF)
exit(2);
printf ("decimal %d\n",a);
getch ();
}





4. Re: Binario negativo

Paulo
paulo1205

(usa Ubuntu)

Enviado em 24/01/2013 - 14:38h

A única chance de você receber um valor negativo com fgetc() é receber a marca de fim de arquivo (EOF) ou um erro de leitura. Veja o que diz a documentação da função.

fgetc() reads the next character from stream and returns it as an unsigned char cast to an int, or EOF on end of file or error.


Foi você também que gerou o arquivo? Se sim, é bom lembrar que o análogo vale também para fputc().

fputc(c, stream) writes the character c, cast to an unsigned char, to stream.



5. Re: Binario negativo

MARCOS
gellox

(usa Outra)

Enviado em 24/01/2013 - 14:45h

Não fui eu quem gerou o arquivo, mas o valor é negativo pois temos outros programas aqui que leem o arquivo.
se eu não consigo ler com fgetc(), você sabe outra maneira de poder ler esse arquivo?
me falaram que poderia ser complemento de 2, que o bit mais significativo informa o sinal.


6. Re: Binario negativo

Perfil removido
removido

(usa Nenhuma)

Enviado em 24/01/2013 - 15:16h

Para trazer o valor de complemento de dois para decimal terá que usar funções que manipulam binários...

A explicação é essa:


00001010 (número 10 em binário)

Para obter o valor NEGATIVO de 10 faça o complemento de 2...


1 - Primeiro inverta o número TODO

11110101 (número 10 invertido)

2 - Depois some + 1 (soma binária) nele

11110101 + 1 = 11110111 (isso é -10 em complemento de dois)

3 - O primeiro número da esquerda para direita (numa arquitetura Little Endian) é chamado de MSB - Bit Mais Significante.

No caso o primeiro bit da esquerda representa o sinal de negativo (-)...

1110111 (-10 em binário)
|
|
|-> MSB - Representa o Sinal Negativo


Agora para trazer o número completado de dois de volta para decimal

1 - Vá repetindo os valores até encontar o primeiro 1

2 - Inverta tudo que encontar depois do primeiro 1

Neste caso o primeiro número já é 1....então inverta TUDO depois dele


Seguindo a regra acima temos o número de volta...


0001001 = 10 em decimal



7. Re: Binario negativo

MARCOS
gellox

(usa Outra)

Enviado em 24/01/2013 - 15:23h

Excelente explicação, porém não sei como implementar.
Poderia me ajudar ??
Outra coisa, como imprimir a variável contendo esse valor em binário (-10), porque o printf ("%d",var) faz a conta com os oito bitis ignorando o sinal de magnitude

Obrigado!


8. Re: Binario negativo

Perfil removido
removido

(usa Nenhuma)

Enviado em 24/01/2013 - 15:27h

Infelizmente não sou programador... só um curioso fuçador...


9. Re: Binario negativo

Paulo
paulo1205

(usa Ubuntu)

Enviado em 24/01/2013 - 16:40h

Qual o valor impresso pelo programa?


10. Re: Binario negativo

MARCOS
gellox

(usa Outra)

Enviado em 25/01/2013 - 07:39h

Pessoal, abaixo segue o código e sua saída. Sei que o valor nessas duas variáveis deverá me retornar -10000, só não estou conseguindo chegar a esse valor, além do complemento de dois tem o big endiam.

Para números positivos resolvi da seguinte forma:

>>>>>>>>>>>Código funcionando para números positivos<<<<<<<<<<<

int main()
{

arq = fopen("arq.bin", "rb");
if (arq==NULL)
{
printf("Erro ao abrir arquivo!!!\n");
system("pause");
exit(1);
}

a=fgetc(arq);
b=fgetc(arq);
total=(a*256)+b;
printf("%d",total);
}


Só que para valores negativos isso não funciona, então fiz um código apenas para mostrar o bits (de cada byte) e o valor em decimal(de cada byte).
Primeiro coloquei a saída e depois o código, preciso de ajuda para chegar ao valor -10000:


>>>>>>>>>>>>>>>Resultado<<<<<<<<<<<<
BYTE 1:
binario 11011000
decimal 216

BYTE 2:
binario 11110000
decimal 240

>>>>>>>>>>>>>>>código<<<<<<<<<<<<<

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <conio.h>

int bit1, bit2, bit3, bit4, bit5, bit6, bit7, bit8;
unsigned char a, b;
FILE *arq;

int main()
{

arq = fopen("arq.bin", "rb");
if (arq==NULL)
{
printf("Erro ao abrir arquivo!!!\n");
system("pause");
exit(1);
}

//1° byte

a=fgetc(arq);
bit8 = (a >> 7) & 1; //10000000
bit7 = (a >> 6) & 1; //01000000
bit6 = (a >> 5) & 1; //00100000
bit5 = (a >> 4) & 1; //00010000
bit4 = (a >> 3) & 1; //00001000
bit3 = (a >> 2) & 1; //00000100
bit2 = (a >> 1) & 1; //00000010
bit1 = (a) & 1; //00000001

printf("BYTE 1:\binario %d%d%d%d%d%d%d%d\n", bit8,bit7,bit6,bit5,bit4,bit3,bit2,bit1);
printf ("decimal %d\n\n",a);

//2°byte

b=fgetc(arq);
bit8 = (b >> 7) & 1; //10000000
bit7 = (b >> 6) & 1; //01000000
bit6 = (b >> 5) & 1; //00100000
bit5 = (b >> 4) & 1; //00010000
bit4 = (b >> 3) & 1; //00001000
bit3 = (b >> 2) & 1; //00000100
bit2 = (b >> 1) & 1; //00000010
bit1 = (b) & 1; //00000001
printf("BYTE 2:\binario %d%d%d%d%d%d%d%d\n", bit8,bit7,bit6,bit5,bit4,bit3,bit2,bit1);
printf ("decimal %d\n",b);

getch ();
}



11. Re: Binario negativo

Paulo
paulo1205

(usa Ubuntu)

Enviado em 27/01/2013 - 23:29h

Você está mexendo com representação de inteiros em baixo nível. Essa representação não é do C, mas uma característica do próprio processador que transparece quando você escolhe trabalhar com bytes individuais.

C, de acordo com os padrões de 1999 e 2011, tem cinco tipos de inteiros: char, short, int, long e long long. Cada um desses tipos admite três variações: signed, unsigned ou não-especificado (que pode, dependendo da arquitetura, ser com sinal ou sem sinal, mas o compilador deve emitir diagnóstico quando alguém misturar na mesma operação um operando com especificação de sinal e outro com sinal não-especificado, mesmo que internamente eles sejam idênticos). Como C é uma linguagem de desenvolvimento de sistemas, esses tipos devem refletir os tipos nativos da máquina em que executam da melhor maneira possível, e por isso mesmo o padrão não força a representação interna de nenhum desses tipos, além dos seguintes requisitos mínimos:

- um char é o menor elemento endereçável pela máquina que tenha pelo menos oito bits (há máquinas em que o char tem nove bits, mas nenhuma em que ele tenha sete ou menos);
- sizeof(char)&#8804;sizeof(short)&#8804;sizeof(int)&#8804;sizeof(long)&#8804;sizeof(long long).

Veja na seguinte tabela algumas representações comuns no PC.


16bit 32bit 64bit
sizeof(char) 1 1 1
sizeof(short) 2 2 2
sizeof(int) 2 4 4
sizeof(long) 4* 4 8
sizeof(long long) N/A@ 8* 8
Notas:
  @ Não sei dizer pois não havia long long na época em que eu usava compiladores de 16 bits no MS-DOS.
  * O tipo de dados existe, mas não corresponde a um tipo nativo do processador. As operações com tamanho final oferecido pelo tipo têm de ser sintetizadas a partir de operações com operandos usando tipos nativos menores.


Dito isso, se você realmente quer ler byte a byte um inteiro com sinal composto por mais de um byte, terá de saber como o seu processador representa internamente um inteiro. Ou seja: tem de saber quantos bytes compõem o número, em que ordem eles são dispostos e de que modo os números negativos são representados. Num PC com processador Intel, usa a notação de complemento a dois para núemros negativos (isto é: -n==(~n)+1), e o byte menos significativo ocupa a menor posição de memória, seguido do segundo byte menos significativo, até o byte mais significativo, por último. Essa é a disposição chamada de little endian. Algumas aplicações, como, por exemplo, a própria disposição de dados nos pacotes de rede da Internet, usam big endian, que significa que os bytes mais significativos aparecem primeiro, e os menos significativos por último.

Então, quando você quer ler o seu valor de -10000, quer fazê-lo a partir de um signed short, de um signed int, signed long ou signed long long? Saber isso é o primeiro passo, para que você saiba quantos bytes deve ler.

O segundo passo é simplesmente compor os bytes lidos numa variável com o tipo adequado. Se esse tipo for signed int e você estiver numa máquina de 32 bits, serão quatro bytes consecutivos com os devidos deslocamentos. Se for little endian, como nos nossos PCs, então o que você deve fazer simplesmente um OU bit-a-bit dos quatro bytes justapostos, e, nesse caso, você não terá de preocupar-se com o sinal do número, pois a simples recomposição do dado original fará com que ele fique íntegro novamente.

Mas tudo ficará muito mais fácil se você fizer a leitura com fread() ou se usar union.






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts