바이트 인라인에서 재 조립 된 플로트
-
19-09-2019 - |
문제
나는 PIC32MX 시리즈의 마이크로 프로세서에서 Hitech PICC32와 함께 일하고 있지만 C에서 지식이있는 사람에게는이 질문이 일반적이라고 생각합니다 (이것은 C90과 거의 같습니다. ) = 4.)
내가 float
. 다음과 같이 실제 플로트 값으로 빠르게 변환 할 수 있습니다.
#define FLOAT_FROM_WORD(WORD_VALUE) (*((float*) &(WORD_VALUE)))
그러나 이것은 LValues에만 적용됩니다. 예를 들어, 다음과 같은 기능 리턴 값에서 사용할 수는 없습니다.
FLOAT_FROM_WORD(eeprom_read_word(addr));
기능 호출 또는 임시 변수가없는이 인라인을 수행하는 짧고 달콤한 방법이 있습니까? 솔직히 말해서, 기능 호출이나 추가 VAR을 피할 큰 이유는 없지만, 나를 괴롭히는 것입니다. 내가 놓친 방법이 있어야합니다.
추가 : 나는 그것을 몰랐다 WORD
실제로 일반적인 typedef였습니다. 혼란을 피하기 위해 매크로 주장의 이름을 변경했습니다.
해결책
반환 값의 다른 방법으로 트릭을 실행할 수 있습니다.
float fl;
*(int*)&fl = eeprom_read_word(addr);
또는
#define WORD_TO_FLOAT(f) (*(int*)&(f))
WORD_TO_FLOAT(fl) = eeprom_read_word(addr);
또는 R Samuel Klatchko가 제안한 것처럼
#define ASTYPE(type, val) (*(type*)&(val))
ASTYPE(WORD,fl) = eeprom_read_word(addr);
다른 팁
이것이 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
깔끔하지만 포송 할 수없는 속임수 인 캐스팅은 "원하는 방식"을 할 수있는 방법이 없으며 다른 답변은 이미 그것을 얻었습니다.
const 참조를 사용하는 경우 임시 가치의 주소를 취할 수 있습니다.
FLOAT_FROM_WORD(w) (*(float*)&(const WORD &)(w))
그러나 그것은 C :(
(C는 참조가 맞지 않습니까? Visual C ++에서 작동)
다른 사람들이 말했듯이, 그것은 정의의 내려 된 기능이거나 온도이든, 컴파일러는 그것을 최적화합니다.
실제로 대답이 아니라 더 많은 제안. float_from_word 매크로는 사용하기가 더 자연스럽고 A가없는 경우 더 유연합니다. 결국
#define FLOAT_FROM_WORD(w) (*(float*)&(w))
fl = FLOAT_FROM_WORD(wd);
정확한 상황에서는 불가능할 수 있지만 C99 컴파일러로 업그레이드하면 문제가 해결됩니다.
C99는 매개 변수 및 반환 값에서 정상적인 함수와 같은 작용하면서 매크로의 단점이 없어서 정확히이 경우 효율성을 향상시키는 인라인 함수를 가지고 있습니다.