Мое плавающее значение не соответствует моему значению в C - PullRequest
4 голосов
/ 20 июня 2019

Я пытаюсь соединить плату с малиной. Я должен читать / записывать значение на плату через Modbus, но я не могу записать значение с плавающей запятой, как плата.

Я использую C и перспективу отладки Eclipse, чтобы увидеть значение переменной напрямую. Доска отправляет мне 0x46C35000, значение которого должно быть 25'000 Dec, но затмение показывает мне 1.18720512e + 009 ...

Когда я пытаюсь на этом сайте http://www.binaryconvert.com/convert_float.html?hexadecimal=46C35000, я получаю 25000.

В чем проблема? Для тестирования я использую это:

int main(){

    while(1){ // To view easily the value in the debug perspective 
        float test = 0x46C35000;
        printf("%f\n",test);
    }
    return 0;
}

Спасибо!

Ответы [ 4 ]

6 голосов
/ 20 июня 2019

Когда вы делаете это:

float test = 0x46C35000;

Вы устанавливаете значение в 0x46C35000 (десятичное число 1187205120), а не представление .

Вы можете делать то, что вы хотите, следующим образом:

union {
    uint32_t i;
    float f;
} u = { 0x46C35000 };

printf("f=%f\n", u.f);

Это позволяет безопасно интерпретировать 32-битное значение без знака как float.

4 голосов
/ 20 июня 2019

Вы путаете логическое значение и внутреннее представление. Ваши назначения устанавливают значение , которое после этого составляет 0x46C35000, то есть 1187205120.

Чтобы установить внутреннее представление числа с плавающей запятой, необходимо сделать несколько предположений о том, как числа с плавающей запятой представляются в памяти. Предположения на веб-сайте, который вы используете (IEEE 754, 32-разрядная версия), справедливы для компьютеров общего назначения.

Чтобы изменить внутреннее представление, используйте memcpy, чтобы скопировать необработанные байты в число с плавающей точкой:

// Ensure our assumptions are correct:

#if !defined(__STDC_IEC_559__) && !defined(__GCC_IEC_559)
#    error Floating points might not be in IEEE 754/IEC 559 format!
#endif

_Static_assert(sizeof(float) == sizeof(uint32_t), "Floats are not 32 bit numbers");
float f;
uint32_t rep = 0x46C35000;
memcpy(&f, &rep, sizeof f);
printf("%f\n", f);

Вывод: 25000.000000.

(для этого требуется заголовок stdint.h для uint32_t и string.h для memcpy.)

3 голосов
/ 20 июня 2019

Константа 0x46C35000, присваиваемая float, будет неявно преобразовывать значение int 1187205120 в float, вместо непосредственного наложения битов в формат с плавающей запятой IEEE-754.

Обычно я использую union для такого рода вещей:

typedef union xFU
{
    float f;
    uint32_t i;
} FU;

int main()
{
    FU foo;

    foo.f = 25000.0;
    printf("%.8X\n", foo.i);

    foo.i = 0x46C35000;
    printf("%f\n", foo.f);

    return 0;
}

Выход:

46C35000
25000.000000
0 голосов
/ 21 июня 2019

Вы можете понять, как данные представляются в памяти, когда вы обращаетесь к ним через их адрес:

#include <stdio.h>

int main()
{
    float f25000; // totally unused, has exactly same size as `int'
    int i = 0x46C35000; // put binary value of 0x46C35000 into `int' (4 bytes representation of integer)
    float *faddr; // pointer (address) to float
    faddr = (float*)&i; // put address of `i' into `faddr' so `faddr' points to `i' in memory

    printf("f=%f\n", *faddr); // print value pointed bu `faddr'

    return 0;
}

и результат:

$ gcc -of25000 f25000.c; ./f25000
f=25000.000000

Что это такое: положить 0x46C35000 в int i

скопировать адрес i в faddr, который также является адресом, который указывает данные в памяти, в данном случае float type

указан параметр печатина faddr;трактуйте это как float тип

и вы получите 25000.0.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...