Skocz do zawartości

Konwersje array to bytes i bytes to array


Pomocna odpowiedź

Napisano

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ć.

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.

(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

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".

(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

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).

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

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?

(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

Ź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

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...