Собрать поплавок из байтов - PullRequest
5 голосов
/ 10 февраля 2010

Я работаю с HiTech PICC32 на микропроцессорах серии PIC32MX, но я думаю, что этот вопрос достаточно общий для тех, кто знает язык C. (Это почти эквивалентно C90 с sizeof (int) = sizeof (long) = sizeof (float) = 4.)

Допустим, я прочитал 4-байтовое слово данных, которое представляет float. Я могу быстро преобразовать его в фактическое значение с плавающей запятой с помощью:

#define FLOAT_FROM_WORD(WORD_VALUE) (*((float*) &(WORD_VALUE)))

Но это работает только для lvalues. Я не могу, например, использовать это на возвращаемом значении функции как:

FLOAT_FROM_WORD(eeprom_read_word(addr));

Есть ли короткий и приятный способ сделать это встроенным, то есть без вызова функции или временной переменной? Честно говоря, у меня нет ОГРОМНОЙ причины избегать вызова функции или дополнительных переменных, но это меня беспокоит. Должен быть способ, которым я скучаю.

Добавлено: Я не осознавал, что WORD на самом деле был обычным typedef. Я изменил имя аргумента макроса, чтобы избежать путаницы.

Ответы [ 5 ]

8 голосов
/ 10 февраля 2010

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

float fl;
*(int*)&fl = eeprom_read_word(addr);

или

#define WORD_TO_FLOAT(f)  (*(int*)&(f))

WORD_TO_FLOAT(fl) = eeprom_read_word(addr);

или, как предлагает Р. Самуэль Клатчко

#define  ASTYPE(type, val) (*(type*)&(val))
ASTYPE(WORD,fl) = eeprom_read_word(addr);
3 голосов
/ 10 февраля 2010

Если бы это был GCC, вы могли бы сделать это:

#define atob(original, newtype) \
  (((union { typeof(original) i; newtype j })(original)).k)

Вау.Уродство.Но использование хорошо:

int i = 0xdeadbeef;
float f = atob(i, float);

Могу поспорить, что ваш компилятор не поддерживает ни оператор typeof, ни приведение union, которое делает GCC, поскольку ни стандартное поведение, ни ввероятность того, что ваш компилятор может выполнить union приведение, это ваш ответ.Изменено, чтобы не использовать typeof:

#define atob(original, origtype newtype) \
  (((union { origtype i; newtype j })(original)).k)

int i = 0xdeadbeef;
float f = atob(i, int, float);

Конечно, это игнорирует проблему того, что происходит, когда вы используете два типа разных размеров, но ближе к «что вы хотите», то есть простой макросфильтр, который возвращает значение, вместо того, чтобы принимать дополнительный параметр.Дополнительные параметры, принимаемые этой версией, приведены только для общности.

Если ваш компилятор не поддерживает приведение union, что является изящным, но непереносимым приемом, то нет способа сделать это "способом".Вы хотите это ", и другие ответы уже получили это.

1 голос
/ 10 февраля 2010

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

FLOAT_FROM_WORD(w) (*(float*)&(const WORD &)(w))

но это не сработает в c: (

(c не имеет ссылок, верно? Работает в Visual C ++)

как уже говорили другие, будь то встроенная функция или темп в определении, компилятор оптимизирует его.

0 голосов
/ 10 февраля 2010

Это может быть невозможно в вашей конкретной ситуации, но обновление до компилятора C99 также решит вашу проблему.

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

0 голосов
/ 10 февраля 2010

Не совсем ответ, скорее предложение. Ваш макрос FLOAT_FROM_WORD будет более естественным в использовании и более гибким, если он не имеет; в конце

#define FLOAT_FROM_WORD(w) (*(float*)&(w))

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