Ir ao conteúdo
  • Cadastre-se

C Como ler conjunto de bytes tipo real escritos em big endian


gellox

Posts recomendados

Pessoal, boa tarde!

 

Gostaria de saber como faço para ler um conjunto de 4 bytes em real de um determinado arquivo escrito em big endiam.

nesse trecho abaixo eu leio um conjunto de 2 bytes inteiros. Entretanto gostaria de ler 4 bytes em float.

Ex:

short int  int2 ; 

arq=fopen("teste","r+b");  

fread (&int2,2,1,arq); 
int2=(int2 << 8 ) | ((int2 >> 8 ) & 0xFF);

printf("%d\n",int2);  

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

@devair1010 arquivo.txtEsse código que postei foi um exemplo eu lendo 2 bytes inteiros e esta correto, mas eu pretendo ler 4 bytes em float e não sei como fazer.


 

ffseek (arq, 70,SEEK_SET);
    fread (&int2,2,1,arq); 
	int2=(int2 << 8) | ((int2 >> 8) & 0xFF);
printf("%d\n",int2);  

resultado = -1

como leio os bytes (226 - 229 ) em floatt???

valor esperado= 719877

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

 

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(int argc, char** argv)
{
	union
	{    float valor;
		 unsigned char bytes[4];
	} u;
	unsigned int N = 0;
	FILE* file = NULL;
	file = fopen("teste.txt","w");
	u.valor = 719877;
	N = fwrite((void*)&u, 4, 1, file);
	printf("Gravou float: %d * %d bytes\n", N, sizeof(float));
	N = fwrite((void*)u.bytes, 1, 4, file);
	printf("Gravou byte a byte: %d bytes\n", N);
	fclose(file);

	file = fopen("teste.txt", "r");
	float outro = 0;

	fread(&outro, 4, 1, file);
	printf("Leu um float: %f\n", outro);

	fread(u.bytes, 1, 4, file);
	printf("Leu em 4 bytes: %f\n", u.valor);

	printf("byte a byte: %X %X %X %X\n",
		u.bytes[0],
		u.bytes[1], 
		u.bytes[2],
		u.bytes[3]
		);
	fclose(file);

	printf("Lendo arquivo original\n");
	file = fopen("arquivo.txt", "r");
	
	unsigned char buffer[256];
	N = fread(buffer, 1, 256, file); // le 240
	printf("Leu %d do arquivo original\n", N);

	for (int i = 220; i <= 236; i += 8)
	{
		printf("%04d    : %02X %02X %02X %02X    %02X %02X %02X %02X\n",
			i,
			buffer[i],
			buffer[i + 1],
			buffer[i + 2],
			buffer[i + 3],
			buffer[i + 4],
			buffer[i + 5],
			buffer[i + 6],
			buffer[i + 7]
		);
	};	// for()
	fclose(file);
};	// main()


Esse programa vai te ajudar a entender o que acontece: Ele grava de duas maneiras esse valor em um arquivo e depois lê e depois abre o arquivo original e mostra a parte que interessa

 

Veja o resultado

Gravou float: 1 * 4 bytes
Gravou byte a byte: 4 bytes
Leu um float: 719877.000000
Leu em 4 bytes: 719877.000000
byte a byte: 50 C0 2F 49
Lendo arquivo original
Leu 256 do arquivo original
0220    : 00 00 00 15    00 45 AF C0
0228    : 50 00 00 00    00 00 00 00
0236    : 00 00 00 00    00 00 00 00

Estão invertidos como esperado, mas tem dois bits de diferença: de AF para 2F e de 45 para 49. Está certo sobre o valor? Sabe a máquina e a linguagem que gerou isso? O formato interno do float é o que importa aqui eu acho.

  • Curtir 1
  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

image.png.fc5f0c856a1f666502139309e3e7cd50.png

Não acha que devia ter postado isso antes? Entendeu o programa que te enviei?

 

Há décadas o padrão para isso é o IEEE754. Veja uma descrição em https://docs.microsoft.com/pt-br/cpp/build/ieee-floating-point-representation?view=vs-2019 por exemplo

 

A FC05 é o valor que quer. Apenas encontre a especificação para o float IBM 4 e converta. Nada tem a ver com Little Endian Big Endian exceto que vai ter claro que inverter os bytes como mostra o programa que te enviei. Se entendeu o programa viu que simplesmente ele grava esse valor de duas maneiras e lê de volta. E depois lê o trecho do seu arquivo onde estão os dados.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Talvez tenha. Fazia tempo que eu não lia nada sobre isso, acho que o formato "754" está bem estabelecido.

 

Mas tem um exemplo aqui: http://www.edwardbosworth.com/My3121Textbook_HTM/MyText3121_Ch17_V02.htm

 

Talvez tenha alguma biblioteca de conversão, veja em http://developer.ibm.com pode ser um bom começo. Mas o formato está bem documentado e não é complicado.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

@gellox Em geral o formato IEEE754 é o formato usado para armazenar números com parte inteira e fracionária na forma binária, o formato IBM de números com ponto flutuante só é usado em mainframes IBM (e mesmo neles IEEE754 também é usado).

 

O software que você está usando está interpretando o conteúdo do arquivo usando o formato IBM (pela imagem aparentemente pode configurar para usar outro formato), usando este formato os bytes usados como exemplo quando convertidos para um número decimal resultarão no número 719877, mas usando o formato IEEE754 resultariam em outro número na forma decimal.

 

A questão é se você está usando o formato correto ao interpretar esse arquivo. Os números foram armazenados no arquivo usando o formato IBM? Se sim você vai ter que implementar o código para fazer a conversão nesse formato.

Link para o comentário
Compartilhar em outros sites

@gellox Não sei se tem biblioteca que faz isso facilmente disponível.

 

Vou explicar a conversão desse exemplo, e você vê se consegue entender para fazer o algoritmo, ou se te ajuda a entender algum algoritmo pronto que você possa aplicar para o seu caso:

 

O código hexadecimal é:

45AFC050

Ou separando cada byte:

45 AF C0 50

Que em binário fica com 32 bits fica:

01000101 10101111 11000000 01010000

Segundo a especificação IBM temos 1 bit para o sinal, 7 bits para o expoente, e 24 bits para a parte fracionária.

 

Sendo que o número é representado como: (-1)sinal x 0.fração x 16(expoente-64)

 

Então separando os bits no formato 1 - 7 - 24 temos:

 

0 1000101 101011111100000001010000

Logo:

Sinal = 0 = 0 hex
Expoente = 1000101 = 45 hex
Fração = 10101111 11000000 01010000 = AF C0 50 hex

Converter o expoente para decimal é simples:

 

45hex = (4dec x 161dec) + (5dec x 160dec) =  69 dec

 

Já o número hexadecimal com parte fracionária é mais complicado:

 

0.AFC050hex

= (0decx160dec) + (10decx16-1dec) + (15decx16-2dec) + (12decx16-3dec) + (0decx16-4dec) + (5decx16-5dec) + (0decx16-6dec)

image.png.5344965cbd1f4eb57ecb361c7e841256.png 

= 0.68652820587158203125dec

 

Logo o número é:

 

(-1)0 x 0.68652820587158203125 x 16(69-64) = (-1)0 x 0.68652820587158203125 x 165 = 719877

 

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

 

 

Aqui, eu fui no embalo e já fiz uma função para converter os 4 bytes = 32 bits do float IBM para IEEE754:

#include <stdio.h>
#include <stdint.h>
#include <math.h>

float IBMfloattoIEEE754 (uint32_t n){
    int sig = (n >> 31) ? -1 : 1;
    uint32_t pot = (n & 0x7F000000) >> 24;
    double frac = (double) (n & 0x00FFFFFF) / 0x01000000;
    return (float) (sig * frac * pow(16.0, pot-64.0));
}

int isBigEndian() {
    int test = 1;
    char *p = (char*)&test;

    return p[0] == 0;
}

uint32_t litEndianUint32_t(uint32_t value){
    uint32_t copy = value;
    if( isBigEndian() ){
        copy = ((copy >> 24) & 0xFF) | ((copy >> 8) & 0xFF00) | ((copy & 0xFF00) << 8) | (copy << 24);
    }
    return copy;
}

int main()
{
    uint32_t n = 0x45AFC050;
    float num = IBMfloattoIEEE754(n);
    
    printf("Numero decimal: %f\n"
           "   Hex IEEE754: %X\n"
           " Hex IBM float: %X\n"
           "Int do Hex IBM: %u\n",
           num, litEndianUint32_t(*(uint32_t *)&num), n, n);
    
    return 0;
}

 

  • Curtir 2
  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

  • 2 semanas depois...

@isrnick  Opa, muito bom e obrigado!

 

Consegui fazer a leitura utilizando o código que me passou, mas vejo que se eu quiser escrever em um arquivo no mesmo formato que li, terei que criar uma outra função que faça o processo inverso!

Onde eu informe um valor, a função converte para que eu possa escrever no arquivo, correto?

  • Curtir 3
Link para o comentário
Compartilhar em outros sites

12 minutos atrás, gellox disse:

Consegui fazer a leitura utilizando o código que me passou, mas vejo que se eu quiser escrever em um arquivo no mesmo formato que li, terei que criar uma outra função que faça o processo inverso!

Onde eu informe um valor, a função converte para que eu possa escrever no arquivo, correto?

 

Sim. 
 

Bom, minha função na verdade deveria se chamar IBMfloattoSystemfloat, afinal numa máquina que não use o formato IEEE754 para o tipo float ela converteria para esse outro formato de tipo float (e imprimiria o número correto de qualquer maneira).

 

Eu não tentei, mas converter no sentido oposto pode não ser tão trivial.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

Ebook grátis: Aprenda a ler resistores e capacitores!

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!