Konwersja z uint8_t na float.

Konwersja z uint8_t na float.
0

Cześć.
Dostaję ramkę danych za pomocą pewnego interfejsu i mam ją zapisana w tablicy typu uint8_t. Załóżmy że pierwsze 4 elementy opisują pierwszą liczbę typu float a kolejne 4 drugą liczbę typu float.
Zazwyczaj robiłem to tak że tworzyłem unię
typedef union
{
uint8_t u8_val[4];
float f_val;
}union_u8_f;

Za pomocą takiej unii konwertowałem 4 elementy typu uint8_t na float. Niestety pewien standard tego zabrania. W jaki sposób dokonać takiej konwersji z czterech liczb typu uint8_t na jednego float'a i na odwrót.

koszalek-opalek
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 2 lata
0
  • Jaki standard tego zabrania?
  • W C++ masz reinterpret_cast (o ile nazwy nie pomieszałem), a w C można coś podobnego rzutowaniem chyba zrobić.
  • Jak nie, to na piechotę -- przeglądać pamięć po bajcie (za pomocą char *) i przenosić między danymi...
edytowany 1x, ostatnio: koszalek-opalek
kq
reinterpret_cast, albo w ogóle cast przez unię w C++ jest nielegalny.
0

Język C++ nie wchodzi w grę.
Standard wewnętrzny oparty na standardzie MISRA C 2004 zabrania użycia unii. Dlaczego? Nie mam pojęcia.

kq
Żeby nie było za prosto. Programiści powinni stosować klauzulę sumienia w takim wypadku, tak samo jak w C++ kazaliby im pisać z użyciem MFC.
0

C

Kopiuj
float myfloat = *( (float*)&uint8_sequence );

C++

Kopiuj
float myfloat = *( reinterpret_cast< float* >( &uint8_sequence ) );
kq
Toto UB jest.
0

Dzięki,
Szerze mówiąc to nie wpadłem na taki sposobu konwersji :). Działa poprawnie, zobaczymy jeszcze czy przejdzie Code Review.

pingwindyktator
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 2 miesiące
  • Lokalizacja:Kraków
  • Postów:1055
1

W C++ takie "castowanie" za pomocą unii to UB.


do not code, write prose
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:4 minuty
  • Lokalizacja:Szczecin
5

Użyj memcpy.

Kopiuj
void to_uint8_t(float f, uint8_t* arr)
{
    memcpy(arr, &f, sizeof(f));
}

void to_float(uint8_t const* arr, float* f)
{
    memcpy(f, arr, sizeof(*f));
}

I zanim zacznie się jojczenie o "wywołania funkcji": https://godbolt.org/g/qMgxu3


Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 2 godziny
1
pingwindyktator napisał(a):

W C++ takie "castowanie" za pomocą unii to UB.

A kompilatory obsługują to jako rozszerzenie.
I słusznie, bo standard jest w tej kwestii nadmiernie restrykcyjny, nie dając właściwie żadnego rozwiązania.
memcpy to nie rozwiązanie, bo jest powolne - niepotrzebnie kopiuje pamięć.

Liczenie na optymalizację kiedy kod wyraźnie mówi coś innego to też nie rozwiązanie.

edytowany 1x, ostatnio: Azarien
kq
Zgadzam się, że to zbędna restrykcja, ale absolutnie nie masz racji w sprawie memcpy - patrz wyżej.
Azarien
Dopisałem co myślę o takim użyciu memcpy.
kq
No spoko, ale albo mówimy o stanie faktycznym (unia działa, ale to ub, memcpy działa, jest legit), albo o teoretycznym standardzie (unia zła, memcpy ok). Nie widzę sensu dla stanów pośrednich. Ponadto takie casty przez unię czasem mogą nie działać i masz problem: http://blog.qt.io/blog/2011/06/10/type-punning-and-strict-aliasing/
Azarien
Przykład z linka na godbolt to jest nadal zbędne kopiowanie (zwłaszcza w przypadku to_float), co jest nie do przyjęcia w sytuacji gdy wydajność jest krytyczna.
kq
Hmm https://godbolt.org/g/J8HZLM Ciekawe, gcc produkuje inny kod tutaj, wyglądający gorzej.
0

Sposób zaproponowany przez użytkowników kQ i undefined reference przeszedł przez Code Review.
Ciekawy tylko jestem co jest złego w zastosowaniu unii w celu rzutowania?

0

Co nie zmienia faktu, że tak jak napisał @kq jest to UB i trzeba mieć oko na te miejsca w kodzie, gdzie jest to użyte.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.