LINUX.ORG.RU

[C][чайник] Снова преобразование типов

 ,


0

1

В продолжение вон того поста .

Читаю с помощью sscanf данные с датчика, расшифровывается правильно все, кроме одного значения. Согласно документации, оно представлено в формате 32-битового числа с плавающей запятой. Делаю так:


float temp;

int scan_result;

scan_result = sscanf(in_buffer, "...%8f...", ...,  &temp, ...);


Однако результат получается совсем не тот, что мне нужен. Например, пришло с датчика число B374C600. Онлайн-перекодировщик говорит, что результат будет -5.6990757e-8, а у меня выходит 4085.0. Что я делаю не так?

>Что я делаю не так?

B374C600

Пытаешься из строки 16ричного формата читать с %f

anonymous
()
Ответ на: комментарий от decadent

Сильно нехороший код - слишком много предположений. Но - работает (i386, little endian, msvc 2005).

#include <stdio.h>

int main(int argc, char *argv[])
{
    int x;
    float f;

    scanf("%x", &x);
    printf("%x\n", x);
    f = *((float *)((void *)&x));
    printf("%e\n", f);
    return 0;
}

Ошибка в понимании - в C нельзя атомарной операцией считать строчку, преобразовать ее в байты и записать в память, отведенную под переменную.

ksv
()
Ответ на: комментарий от anonymous

Кстати, если делать так:

 
scan_result = sscanf(in_buffer, "...%8x...", ...,  &temp, ...); 

то результат правильный, но при этом компилятор ругается:

warning: unsigned int format, float arg

decadent
() автор топика

>Однако результат получается совсем не тот, что мне нужен.

У тебя в строке записано «сырое» представление числа. Ну так и читай в сыром виде: sscanf(«B374C600», «%8x», (int*)&temp);

Хотя надежней так:

#include <inttypes.h>
...
union {int i; float f;} temp;
scan_result = sscanf(in_buffer, "...%8" SCNx32 "...", ...,  &temp.f, ...);
linuxfan
()
Ответ на: комментарий от ksv

f = *((float *)((void *)&x));

Бррр...

Ошибка в понимании - в C нельзя атомарной операцией считать строчку, преобразовать ее в байты и записать в память, отведенную под переменную.

Так ведь с int все работает, вот в чем дело! Проблема в том, что когда я в строке формата использую «%x» — компилятор ожидает, что будет вводиться int (ну, точнее, int *). Я чуть ниже об этом написал. Если вместо этого подставить float — компилятор ругается, но результат получается правильный. Как бы теперь добиться, чтобы он не ругался?

decadent
() автор топика
Ответ на: комментарий от linuxfan

sscanf(«B374C600», «%8x», (int*)&temp);

Вот за эту идею спасибо огромное! Кажется, теперь заработало.

Насчет union — побаиваюсь я их. Я еще не настолько хорошо знаю Си, чтоб с ними активно работать. Хотя, конечно, выглядит красиво.

decadent
() автор топика
Ответ на: комментарий от edigaryev
 
scan_result = sscanf(in_buffer, "...%8x...", ...,  (unsigned int *)&temp, ...);  

Спасибо, так и сделал.

decadent
() автор топика
Ответ на: комментарий от decadent

>«%8x»

Я тебе об этом ещё в первом псте сказал.

anonymous
()
Ответ на: комментарий от decadent

>Насчет union — побаиваюсь я их.

Я страшный union. Бойся меня.

Мне не совсем понятно, чего ты боишься?

З.Ы. Мне кажется, или на форуме расплодилось огромное количество белок. Страшно подумать чем выфер в свободное время занимается.

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder
 
Мне кажется, или на форуме расплодилось огромное количество белок. Страшно подумать чем выфер в свободное время занимается.

Я не выфер, да и жабу я не знаю :-)

decadent
() автор топика
Ответ на: комментарий от pathfinder

Насчет union — побаиваюсь я их.

Мне не совсем понятно, чего ты боишься?

Опасаюсь низкоуровневых операций с памятью, потому как пока что не умею отлавливать возможные утечки. А программа, которую я пишу, должна работать 365/24/7, поэтому стараюсь минимизировать вероятность того, что однажды она зохавает всю память.

decadent
() автор топика
Ответ на: комментарий от decadent

>однажды она зохавает всю память

Да ладно, не бойся - она до этого по sigsegv развалится.

;studies finica

anonymous
()
Ответ на: комментарий от decadent
sscanf("B374C600", "%8x", (int*)&temp);

Насчет union — побаиваюсь я их. Я еще не настолько хорошо знаю Си, чтоб с ними активно работать.

Зато настолько хорошо знаешь C, чтобы смело приводить int к float? Напиши в начало исходника

#ifndef __i386__
#error "I'm lazy"
#endif

С union не лучше, конечно. Тут лучше руками все байтики разложить, а не надеяться, что они сами попадут куда хочется.

const86 ★★★★★
()
Ответ на: комментарий от decadent

>Опасаюсь низкоуровневых операций с памятью, потому как пока что не умею отлавливать возможные утечки. А программа, которую я пишу, должна работать 365/24/7, поэтому стараюсь минимизировать вероятность того, что однажды она зохавает всю память.

Может я чего-то не понимаю, но я по прежнему не вижу ничего страшного в union. Эта sscanf(), которую ты активно используешь, действительно страшная штука.

А программа, которую я пишу, должна работать 365/24/7

Сочувствую. Но это хорошо, что ты осознаешь «особые» требования к ПО, которое должно работать в таком режиме. :)

pathfinder ★★★★
()

Я уже сказал в предыдущей теме, что scanf() использовать не надо. Надо работать непосредственно с байтами строки. Так будет проще и надежнее.

Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.