Ir ao conteúdo

Posts recomendados

Postado

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
Postado

@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
Postado

trata-se apenas de inverter os bytes e as palavras. Você tem um arquivo que foi gerado assim? Big Endian? De que máquina?

Sabe ler um dump ou usar um editor hex? 

 

  • Curtir 1
Postado

 

#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
Postado

@arfneto Sim, tenho certeza do valor! Estou enviando a foto de um aplicativo que le esses valores corretamente, note que a primeira coluna esta em float e a segunda li os mesmos bytes em int!


 

imagem1.JPG.895c7d3e9464bad25cef67b81d535352.JPGimagem2.JPG.8cfece055e3b8831b0609365715a3c73.JPG

  • Curtir 1
Postado

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
Postado

@arfneto Qto a inversão de bytes entendi sim, mas ainda não sei como sobre o padrão IEEE754, vou estudar o link que me enviou e vejo se descubro algo

 

adicionado 29 minutos depois

@arfneto Inclusive achei que poderia haver alguma biblioteca que fizesse isso automaticamente

  • Curtir 1
Postado

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
Postado

@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.

Postado

@isrnick Sim  "os números foram armazenados no arquivo usando o formato IBM", I

"implementar o código para fazer a conversão nesse formato" = isso eu entendi, só não sei como implementar esse código, por isso ate perguntei se ja existia uma biblioteca que fizesse isso.

  • Curtir 1
Postado

@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
Postado

 

 

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
  • 2 semanas depois...
Postado

@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
Postado
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

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...

LANÇAMENTO!

eletronica2025-popup.jpg


CLIQUE AQUI E BAIXE AGORA MESMO!