Skocz do zawartości
jordanj

Konwersje array to bytes i bytes to array

Pomocna odpowiedź

Cześć, muszę zapisać tablicę, najprościej to zrobić jako bytes i już drugi wieczór męczę się aby z tablicy zrobić bajty i vice versa. Tablica zawiera elementy int8_t czyli 8-bitowe liczby całkowite ze znakiem.

Robię tak:

Deklaruję jakąś tablicę:

  int8_t OTCoutdoorArray[10];
  int8_t OTCsupplyArray[10];
  uint8_t OTCentries;

Gdzieś do tych tablic przypisuję wartości, tablice wyświetlam za pomocą pętli for i widzę, że te wartości się tam znajdują.

Przypisuję do niej takie wartości.

21 20
18 25
15 30
0 40
-10 50
-20 55
-30 65

Próbuję zamienić te tablice na ciąg bajtów.

      void *oBytes;
      void *sBytes;
      oBytes = (int8_t *)OTCoutdoorArray;
      sBytes = (int8_t *)OTCsupplyArray;

Następnie te ciągi bajtów próbuję zamienić na tablice.

      int8_t (*oArray)[OTCentries] = (int8_t (*)[OTCentries]) oBytes;
      int8_t (*sArray)[OTCentries] = (int8_t (*)[OTCentries]) sBytes;

... i sprawdzam w pętli efekt działania tych przekształceń.

for(int i = 0; i<OTCentries; i++) {
        Serial.println(String(OTCoutdoorArray[i]) + " " + String(OTCsupplyArray[i]) + " " + String(*oArray[i]) + " " + String(*sArray[i]));
}

W rezultacie dostaję taki wynik:

21 20 21 20
18 25 0 30
15 30 50 -37
0 40 30 0
-10 50 8 -5
-20 55 -128 0
-30 65 -5 0

Dwie pierwsze kolumny prezentują dane z tablic bez przekształceń do ciągu bitów, a dwie kolejne po przekształceniu i powrocie do tablic. Pierwsza linijka jest OK, a dalej się coś pieprzy. Już straciłem pomysły dlaczego to nie działa - moja znajomość C++ jest dość podstawowa, szczególnie w zakresie bitwise operations - wstyd się przyznać.

Udostępnij ten post


Link to post
Share on other sites

Nie do końca rozumiem co chcesz osiągnąć. Po co chcesz zamieniać tablicę typów int8_t na ciąg bajtów - skoro twoja tablica typów int8_t jest ciągiem bajtów sama w sobie - więc masz to tak jakby w gratisie. Chyba że przez 'bajt' rozumiemy liczbę bez znaku (0 - 255), co nadal nie zmienia faktu, że tablica jest ciągiem bajtów.

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

Nieprecyzyjnie się wyraziłem. Muszę coś zapisać do eepromu, ta funkcje jako argument potrzebuje danych do zapisania typu const void *. ..., a zatem z int8_t[10] muszę zrobić const void* i vice versa.

Edytowano przez jordanj

Udostępnij ten post


Link to post
Share on other sites

Ty nie masz nic robić, Tobie potrzebne jest po prostu rzutowanie.

Poza tym może napiszesz jakiej platformy używasz to będzie łatwiej coś powiedzieć, bo ani w C ani w C++ nie ma w standardzie czegoś takiego jak "pisanie do eepromu".

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

Okej, zatem void * oznacza wskaźnik na nieokreślony typ, Ty jako programista musisz zadbać na na jaki typ ten wskaźnik będzie wskazywał wykorzystując rzutowanie - więcej info: https://pl.wikipedia.org/wiki/Pusty_typ_danych#Definiowanie_wskaźników_do_danych_nieokreślonego_typu

A przykładowe pisanie do abstrakcyjnego EEPROMu może wyglądać tak (uruchom w kompilatorze C++):

// Example program
#include <iostream>
#include <string>
#include <cstring>

static uint8_t eepromMemory[256];

void write(const void* source, uint8_t size, uint8_t startIndex)
{
    memcpy((eepromMemory + startIndex), source, size);
}

void read(void* destination, uint8_t size, uint8_t startIndex)
{
    memcpy(destination, eepromMemory + startIndex, size);
}

int main()
{
    int8_t dataToSave[4] = {-1, 0, 1, 2};
    int8_t dataFromEeprom[4];

    for(uint8_t i = 0; i < 4; i++)
    {
        printf("Item to save: %d \tValue: %d\n", i, dataToSave[i]);
    }
    printf("\n");

    // rzutuje dataToSave na const void*
    write(reinterpret_cast<const void*>(dataToSave), 4*sizeof(int8_t), 5);

    for(uint8_t i = 0; i < 20; i++)
    {
       printf("Item in EEPROM: %d \tValue: %d\n", i, eepromMemory[i]);
    }
    printf("\n");

    // rzutuje dataFromEeprom na void*
    read(reinterpret_cast<void*>(dataFromEeprom), 4*sizeof(int8_t), 5);

    for(uint8_t i = 0; i < 4; i++)
    {
        printf("Item retrieved from EEPROM: %d \tValue: %d\n", i, dataFromEeprom[i]);
    }

    return 0;
}

Efekt:

Item to save: 0 	Value: -1
Item to save: 1 	Value: 0
Item to save: 2 	Value: 1
Item to save: 3 	Value: 2

Item in EEPROM: 0 	Value: 0
Item in EEPROM: 1 	Value: 0
Item in EEPROM: 2 	Value: 0
Item in EEPROM: 3 	Value: 0
Item in EEPROM: 4 	Value: 0
Item in EEPROM: 5 	Value: 255
Item in EEPROM: 6 	Value: 0
Item in EEPROM: 7 	Value: 1
Item in EEPROM: 8 	Value: 2
Item in EEPROM: 9 	Value: 0
Item in EEPROM: 10 	Value: 0
Item in EEPROM: 11 	Value: 0
Item in EEPROM: 12 	Value: 0
Item in EEPROM: 13 	Value: 0
Item in EEPROM: 14 	Value: 0
Item in EEPROM: 15 	Value: 0
Item in EEPROM: 16 	Value: 0
Item in EEPROM: 17 	Value: 0
Item in EEPROM: 18 	Value: 0
Item in EEPROM: 19 	Value: 0

Item retrieved from EEPROM: 0 	Value: -1
Item retrieved from EEPROM: 1 	Value: 0
Item retrieved from EEPROM: 2 	Value: 1
Item retrieved from EEPROM: 3 	Value: 2

 

Edytowano przez Matthew11
Poprawka
  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Teraz akurat używam ESP32 i tam jest w Arduino zarówno klasa do zapisywania do EEPROMu bezpośrednio (podając adres) jak i owrapowane preferencje (wygodniejsze bo ma to strukturę key -> value). Key jest char*, a value może być char, int i wiele innych, a w ostateczności const void*. Do tego używam dwóch funkcji:

size_t getBytes(const char* key, void * buf, size_t maxLen);
size_t putBytes(const char* key, const void* value, size_t len);

Czyli mam sobie jakąś tablicę, np. rzeczoną int8_t[10] i muszę do niej stworzyć wskaźnik (pointer).

Udostępnij ten post


Link to post
Share on other sites

No to właśnie do tego służy rzutowanie...

Coś w stylu:

int8_t tablica[10];
const char *key="...";
...
putBytes(key, (const void *) tablica, 10);
...
getBytes(key, (void *)tablica, 10); // w C nie trzeba by było nawet rzutowania, ale to C++

 

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Dlaczego w getBytes jest rzutowanie tablicy na typ void* ? Przecież ona zwraca typ void, więc rzutowanie powinno by raczej na int8_t[10] czy mi się źle wydaje?

Udostępnij ten post


Link to post
Share on other sites
(edytowany)
4 minuty temu, jordanj napisał:

Dlaczego w getBytes jest rzutowanie tablicy na typ void* ? Przecież ona zwraca typ void, więc rzutowanie powinno by raczej na int8_t[10] czy mi się źle wydaje?

getBytes zwraca size_t jeśli mamy być poprawni, ale przyjmuje void * buf, więc rzutujesz na void* -> getBytes(key, (void *)tablica, 10);

Edytowano przez Matthew11
Poprawa na język polski...
  • Lubię! 2

Udostępnij ten post


Link to post
Share on other sites

Źle Ci się wydaje.

Nie rzutujemy tablicy na typ, tylko typ "wskażnik do char" (bo tym jest w tym przypadku tablica) na typ "wskaźnik do void".

Funkcja nic nie zwraca (w szczególności żadnego typu), tylko wypełnia podane miejsce w pamięci (adres) jakąś tam zawartością. A ponieważ jako adresu oczekuje wskaźnika do void (w C to synonim "wskaźnik do dowolnej danej"), taki typ argumentu jej należy podać.

  • Lubię! 2

Udostępnij ten post


Link to post
Share on other sites

Bardzo dziękuję za wyjaśnienie, oczywiście działa. 🙂

Udostępnij ten post


Link to post
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Gość
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.


×
×
  • Utwórz nowe...