Převod řetězce do struktury – C / C++ – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Převod řetězce do struktury – C / C++ – Fórum – Programujte.comPřevod řetězce do struktury – C / C++ – Fórum – Programujte.com

 

Pavelv0
Stálý člen
29. 1. 2018   #1
-
0
-

Zdravím, potřebuji nějakým způsobem uložit přijatý řetězec odpovídacící hexa tvaru do struktury. Vysvětlím to na příkladu.

Mám strukturu  

struct
{
uint8_t		N;
uint8_t		M;
uint16_t	V1;
uint16_t	V2;
uint16_t	V3;
} Item;


a přijatá data ve tvaru "01023C983C973C96".

Výsledek by měl být N = 0x01; M = 0x02; V1 = 0x3C98; V2 = 0x3C97; V3 = 0x3C96.

Převést ASCI HEX na HEX je snadný, jak ale roztřídím ty data, aniž bych použil pevné indexy řetězce? Struktura má ve skutečnosti 60 prvků, a je to směs 8 a 16 bitů.

Napadlo mě využít union a 8bit pole se stejnou šířkou jako je struktura. Bohužel ale bitová orientace není 1:1. Mám prohozený horní byte se spodním. Obsah N a M je v pořádku, ale ve V1 je 0x983C. Má C++ nějaký lepší nástroj na procházení prvků struktury?

Nahlásit jako SPAM
IP: 185.99.177.–
KIIV
~ Moderátor
+43
God of flame
29. 1. 2018   #2
-
0
-

#1 Pavelv
Lepsi nastroj na prochazeni prvku struktury? Dalo by se pouzit neco jako offsetof, nicmene jednotlive prvky muzou byt zarovnane. Takze je dost mozne, ze N, M budou za sebou, ale mezi M a V1 bude 2B mezera.

Kazdopadne nejak snadno se to udelat uplne neda. Pokud vim, tak C++ nedisponuje potrebnou "reflexi".

Muzes si treba udelat program, ktery by ti vse vygeneroval podle nejakeho predpisu (neco jako preprocesor).

Dalsi moznosti je nepouzivat primo polozky struktury, ale pole nebo asociativni pole. To se pak da serializovat mnohem lepe, jelikoz to zna vsechny prvky. Pri pouziti polymorfizmu si kazda polozka veme co potrebuje a zbytek necha dalsimu v poradi.

Nahlásit jako SPAM
IP: 185.163.41.–
Program vždy dělá to co naprogramujete, ne to co chcete...
MilanL+1
Grafoman
29. 1. 2018   #3
-
0
-

#1 Pavelv
ahoj, 

"Obsah N a M je v pořádku, ale ve V1 je 0x983C" - dáno formátováním čísel little-endian, kdy se u více Bajtových čísel otáčí pořadí Bytů, viz https://cs.wikipedia.org/wiki/Endianita.

#2 KIIV
neexistuje nějaká direktiva, která by označila část kodu, aby se tam čísla ukládala jako big-endian?

Nahlásit jako SPAM
IP: 91.139.9.–
KIIV
~ Moderátor
+43
God of flame
29. 1. 2018   #4
-
0
-

#3 MilanL
jsou na to funkce, pro zmenu endianity. Nicmene pokud to budes prevadet, tak to z toho vyleze spravne.

Nahlásit jako SPAM
IP: 185.163.41.–
Program vždy dělá to co naprogramujete, ne to co chcete...
Pavelv0
Stálý člen
29. 1. 2018   #5
-
0
-

Jasne, funkce jsou mi jasné, ale to pak musím označit všechny prvky struktury, které se budou otáčet. Chtěl jsem univerzální řešení, kterému předhodím strukturu, řetězec znaků a vše se již zařídí samo. Takhle musím hlídat a upravovat i prvky struktury.

Nahlásit jako SPAM
IP: 185.99.177.–
KIIV
~ Moderátor
+43
God of flame
29. 1. 2018   #6
-
0
-

Automaticky by to slo jedine pomoci objektu. I tak bys je musel nakonec nahazet do nejakeho seznamu.

Nahlásit jako SPAM
IP: 185.163.41.–
Program vždy dělá to co naprogramujete, ne to co chcete...
MilanL+1
Grafoman
29. 1. 2018   #7
-
0
-

#4 KIIV
no já myslel pro Pavla, aby mohl použít ten union.

#1 Pavelv
odkud ti ty data lezou, můžeš to ovlivnit, aby ti to ty více bajtové hodnoty poslalo ve správném formátu jako little-endian?

Nahlásit jako SPAM
IP: 91.139.9.–
Pavelv0
Stálý člen
29. 1. 2018   #8
-
0
-

Ovlivnit právě, že nedokážu, bych to jinak už celý překopal. potřebuji takto naimplementovat asi 5 striktur, každá o minimálně 50 prvcích. Takže výsledný kód pro ukládání bude strašně nepřehledný.

Nahlásit jako SPAM
IP: 185.99.177.–
MilanL+1
Grafoman
29. 1. 2018   #9
-
0
-

ještě bych možná viděl jednu variantu názvy ve struktuře jako indexy, místo struktury pole variantů, v inicializaci nastavit variantům poli podle indexů(názvů ve struktuře) typy a pak deserializační funkci, která si ze vstupu vždy podle typu prvku v poli ukrojí a naformátuje co potřebuje..

EDIT: Právě jsem zjistil, že tak jak jsem to myslel by tohle nejspíš nešlo.

Nahlásit jako SPAM
IP: 91.139.9.–
KIIV
~ Moderátor
+43
God of flame
29. 1. 2018   #10
-
0
-

No da se to udelat i jakz takz citelne. Neco ve stylu: http://cpp.sh/8c4wg

Poradi prvku si holt musis urcit poradim v metode fromStream. Velikosti si to zjisti podle datoveho typu.

Nahlásit jako SPAM
IP: 185.163.41.–
Program vždy dělá to co naprogramujete, ne to co chcete...
gna
~ Anonymní uživatel
1891 příspěvků
29. 1. 2018   #11
-
0
-

Jestli jde o lenost to psát, tak spousta editorů má možnost nahrazování ve výběru s použitím regexů, takže si ten kód můžeš vygenerovat.

$ sed -r 's/\s*(\S+)\s+(\S+);/s.\2 = read_\1\(\);/'
> uint8_t         N;
> uint8_t         M;
> uint16_t        V1;
> uint16_t        V2;
> uint16_t        V3;
< s.N = read_uint8_t();
< s.M = read_uint8_t();
< s.V1 = read_uint16_t();
< s.V2 = read_uint16_t();
< s.V3 = read_uint16_t();
Nahlásit jako SPAM
IP: 213.211.51.–
MilanL+1
Grafoman
30. 1. 2018   #12
-
0
-

#11 gna
psal 5 struktur po 50-60 prvcích.

no pokud by to byla směs jen 8 a 16bit čísel řešil bych to unionem a polem ve kterém by bylo podle pořadí rozlišení 8/16bit.

union
{
  unsigned char bytes[8];
  struct
  {
    uint8_t	N;
    uint8_t	M;
    uint16_t	V1;
    uint16_t	V2;
    uint16_t	V3;
  } 
} Item;
int itm1typy [5] = {1,1,2,2,2}

převést vstup na hodnoty do toho bytového pole - to jsi psal, že máš.
a poté to pole projít a podle itm1typy a v požadovaných místech zaměnit

int pbytes = 0;
int tmp;

for (int i=0; i<5; i++)
{
  if itm1typy[i] = 2 
  {
    tmp=item.bytes[pbytes];
    item.bytes[pbytes]=item.bytes[pbytes+1];
    pbytes++;
    item.bytes[pbytes]=tmp;
  }
  pbytes++;
}


pokud tam jsou jen 8 a 16 bitová čísla mělo by stačit tohle, pokud by tam byly dalá typy musela by se odpovídajícím způsobem rozšířit podmínka

Nahlásit jako SPAM
IP: 185.112.167.–
gna
~ Anonymní uživatel
1891 příspěvků
30. 1. 2018   #13
-
0
-

#12 MilanL
Předpokládám, že ty struktury má definované. I kdyby jich bylo třeba milión, tak je stačí transformovat. Klidně na to tvoje debilní pole, když ten union udělá správně.

Nahlásit jako SPAM
IP: 213.211.51.–
Jerry
~ Anonymní uživatel
512 příspěvků
30. 1. 2018   #14
-
0
-

#1 Pavelv
co tohle ?

https://stackoverflow.com/questions/13294067/how-to-convert-string-to-char-array-in-c

Nahlásit jako SPAM
IP: 2a00:1028:83be:235a:ed83:...–
KIIV
~ Moderátor
+43
God of flame
30. 1. 2018   #15
-
0
-

#12 MilanL
smyslem psat kod ma byt citelnost a pochopitelnost umyslu. Ten muj kod aspon funguje a da se pochopit co dela.

No a jak uz sem zminoval, kompilator data casto zarovnava. Muze se stat, ze to bude presne za sebou jak predpokladas, muze se stat, ze tam budou mezery a pak se to cele rozesere. V tvem pripade se aspon da osetrit endianita, ale jinak sebemensi odchylka znamena, ze se vse podela.

Proste, kdyz je v C++, tak je lepsi vyuzit jeho vymozenosti. To ze nekdo z druhe strany posila memory dump pameti, a muze se to kdykoliv rozesrat taky, to je holt klasickej pristup z C.

#14 Jerry
Mimochodem to patri i tomu predchozimu: vis, ze v C++ je struktura jen objekt, s jinak nastavenym defaultnim pristupem k prvkum? Jakmile tam nebudou POD typy, tak takovymhle kopirovanim binarnich dat muzes vsechno rozesrat? A zase se neresi byteorder. V predchozim by se tam dal aspon pridat, u tebe pak budes mit extra funkci pro jeho opravovani pro kazdy z prvku.

Nahlásit jako SPAM
IP: 81.30.230.–
Program vždy dělá to co naprogramujete, ne to co chcete...
Jerry
~ Anonymní uživatel
512 příspěvků
30. 1. 2018   #16
-
0
-

#15 KIIV
v tom případě bych použil tohle

https://stackoverflow.com/questions/505021/get-bytes-from-stdstring-in-c

Nahlásit jako SPAM
IP: 2a00:1028:83be:235a:745d:...–
KIIV
~ Moderátor
+43
God of flame
30. 1. 2018   #17
-
0
-

#16 Jerry
to jsi asi nepochopil co sem tim myslel. Pokud mas ve strukture nebo objektu (coz je to same) nejake data, ktere nejsou POD (plain old data), tak nemusi mit data primo v sobe. Coz znamena, ze zkopirovanim kusu pameti nedokazes zreplikovat kompletni data. Proste kdyz by v tom byl std::string, jak budes vedet, ze se melo pouzit c_str, kdyz delas jen memcpy nekam?

Nahlásit jako SPAM
IP: 185.163.41.–
Program vždy dělá to co naprogramujete, ne to co chcete...
Jerry
~ Anonymní uživatel
512 příspěvků
30. 1. 2018   #18
-
0
-

#17 KIIV
no ale tak musí mít někde jak dlouhý ty data sou ne ? :))))))))))))) on nemá mozek ?

Nahlásit jako SPAM
IP: 2a00:1028:83be:235a:745d:...–
MilanL+1
Grafoman
30. 1. 2018   #19
-
0
-

No já vycházel ze zadání

 - co nejjednodušší převod hex stringu do struktury.
 - dále jsem předpokládám, že data přichází v pevně daném formátu.
 - union dokonce zkoušel jediný problém měl s tou Endianitou a jejímu ošetření přes nějakou funkci se prostě nevyhne

Samozřejmě v případě dynamického formátu příchozích dat by to musel řešit jinak.


Nahlásit jako SPAM
IP: 91.139.9.–
KIIV
~ Moderátor
+43
God of flame
30. 1. 2018   #20
-
0
-

A ja zase vychazim z toho, ze jde hlavne o citelnost kodu. Radsi budu cist neco takoveho:

#include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include <iterator>

template <typename T> bool fromHex(std::istream& in, T& out)
{
    out = 0;
    for (size_t cnt = 0; sizeof(T)*2 > cnt; ++cnt)
    {
        char ch; 
        in >> ch;
        
        if (ch >= '0' && ch <= '9')
        {
            out = (out<<4) | (ch - '0');
        }
        else if (ch >= 'A' && ch <= 'F')
        {
            out = (out<<4) | (ch - 'A' + 10);
        }
        else if (ch >= 'a' && ch <= 'f')
        {
            out = (out<<4) | (ch - 'a' + 10);
        }
        else
        {
            return false;
        }
    }
    
    return true;
}

struct item
{
    uint8_t   N;
    uint8_t   M;
    uint16_t V1;
    uint16_t V2;
    uint16_t V3;
  
    bool fromStream(std::istream& in)
    {
        return fromHex(in, N)
            && fromHex(in, M)
            && fromHex(in, V1)
            && fromHex(in, V2)
            && fromHex(in, V3);
    }   
};

int main()
{
    item neco = {};
    
    std::istringstream input("EF446677FEAD0001");
    neco.fromStream(input);
    
    std::cout << int(neco.N) << " " << int(neco.M) << " " << neco.V1 << " " << neco.V2 << " " << neco.V3 << "\n";
}

Nez nejaky zahadny prekryvani pomoci unionu nebo  char* itemAsCharString = (char*)&item; a pak zahadne kopirovani kdo vi cim... Takovyhle saskarny se delaji, az kdyz je normalni parsovani prilis pomale.

Nahlásit jako SPAM
IP: 185.163.41.–
Program vždy dělá to co naprogramujete, ne to co chcete...
MilanL+1
Grafoman
30. 1. 2018   #21
-
0
-

#20 KIIV
hezký elegantní řešení - já C++ používám málo a templaty už vůbec, ale když vidím tohle, tak se na to budu muset kouknout.

Jen při těch 60 nebo kolika prvcích struktury mu to trošku naroste, ale mě by to nevadilo.

Nahlásit jako SPAM
IP: 91.139.9.–
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 63 hostů

Podobná vlákna

Převod struktury na char — založil Sprinter

Struktury — založil Matěj Andrle

Struktury — založil Samuel Lehotský

Moderátoři diskuze

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý