ByteArray in der STL oder BOOST?



  • Hi! Ich suche eine Klasse die binäre Daten verarbeiten kann.
    In Actionscript 3 gibt es eine Klasse ByteArray. Mit dieser kann man dann mit readInt, writeInt, readDouble, writeDouble, readFloat, readShort, readUTFString, etc. bytes lesen und schreiben. Gibt es sowas auch in der STL oder mit BOOST?

    Ich könnte ein std::vector<char> als ByteArray benutzen und dann eine klasse drum herum basteln, müsste dann aber alle Methoden selber schreiben...

    Gibt es da was?


  • Mod

    Was machen die Funktionen? Die klingen vom Namen her so, als wäre das eher ein Feature, um in weniger maschinennahen Sprachen das nachzubauen, wie sich Daten in C++ ganz normal von Natur aus verhalten.



  • Hallo,

    s. letztes Kapitel unter C++ Binary File I/O, d.h. also per istream.read.
    Nur für das Auslesen null-terminierter (UTF-)Strings müßtest du dann istream.getline verwenden (bzw. getline(string) für direktes Einlesen in einen std::string).

    Wenn du keine Datenstruktur direkt benutzt (bzw. benutzen kannst), dann kannst du auch mittels dieses Funktionstemplates das [elegant] nachbauen:

    template<T>
    std::istream read(std::istream &is, T &t)
    {
      return is.read(reinterpret_cast<char*>(&t), sizeof(T));
    }
    

    Aufruf dann z.B.

    int x;
    float y;
    short z;
    std::string s;
    
    read(is, x);
    read(is, y);
    getline(is, s, '\0');
    read(is, z);
    

    Noch eleganter wäre dies mittels einer Wrapper-Klasse, in der diese Funktion dann Member wäre, so daß der std::istream-Parameter nur einmalig im Konstruktor angegeben wird (und dann eine Referenz als Member gehalten wird).
    Dann ginge dies sogar mit fluent-interface à la:

    binary_reader r(is);
    
    r.read(x).read(y).read(z);
    


  • Noch eleganter wäre es dann noch mit variadischen Templates.

    reader r(is);
    r.read(arbitrary, number, of, params);
    


  • Das ist dann die Bonusaufgabe für den TE. 🕶



  • Hallo zusammen,
    ich denke ich habe ein ähnliches Problem, bin mir da aber nicht sicher.

    Ich bin dabei einen Scanner anzusprechen und bekomme von diesem Daten zurück.

    Laut Dokumentation:
    uint16 magic byte
    uint16 packet_size
    unint32header size
    .
    .
    .
    uint32 distance

    Bis jetzt habe ich Daten empfangen, ich habe jeweils ein Datenpaket in einen String gepackt und diese erstmal in eine Liste gepackt. Jetzt möchte ich diese Daten weiterverarbeiten.
    Die Byte Order ist little Endian.

    Nun dachte ich mir das ich eine Klasse baue mit allen Paketdaten und da den String übergebe und jedem Attribut seinen wert aus dem Paket zuweise. Ich habe jedoch keine vollendete Idee wie ich das am besten angehen soll. Meine Überlegung war jedem Attribut erstmal seine Größe mitzugeben und dann durch den String zugehen und Ihn zu zerschneiden....

    Wenn Ihr fragen habt immer her damit. Ich freue mich über jegliche Art von Hilfe



  • dragonfight86 schrieb:

    Bis jetzt habe ich Daten empfangen, ich habe jeweils ein Datenpaket in einen String gepackt

    Das verstehe ich schon nicht. Wieso, weshalb, warum kommt hier plötzlich ein String ins Spiel?



  • Hier mal die Funktion dazu.
    Ich finde es mit String einfach und hatte dazu auch keine Alternative.

    void PaFR2000Scanner :: threadReceive(CThread* pclThread)
    {	
    	CRITICAL_SECTION csCritS;
    	InitializeCriticalSection(&csCritS);
    	string strTestString;
    	string strTemp;
    	int iVal = 0;
    	char cRecv[2048];
    	PaFR2000Scanner* objTmp;
    	// weist Zeiger ein gecastetes Threadobjekt zu
    	objTmp = (PaFR2000Scanner*) pclThread->m_pvThreadObject;
    	//
    	CDebugOutput* debugOut;
    	//
    	debugOut = objTmp->cDebugOutput;
    
    	try
    	{
    		// instanziiert Zeiger auf Scanner Klasse
    
    		do 
    		{
    			if( objTmp->iState == 1 )
    			{
    				iVal = objTmp->cClientTcp->receiveMessage(cRecv,2048);
    				if((-1) != iVal)
    				{
    					if(0x5c ==   ((unsigned char) cRecv[0]) && (0xa2  == (unsigned char) cRecv[1]))
    					{
    
    						if (0 < strTemp.size())
    						{
    							EnterCriticalSection(&csCritS);
    
    							objTmp->listPaket.push_back(strTemp);
    							LeaveCriticalSection(&csCritS);
    							strTemp.clear();
    						}
    						debugOut->debug(0,"Magic Key gefunden");
    						strTemp = cRecv;
    						debugOut->debug(0,cRecv);
    						iVal = 0;
    					}
    					else
    					{
    						strTemp += cRecv;
    						debugOut->debug(0,"strTemp erweitert...",cRecv);
    						iVal = 1;
    					}					
    					Sleep(0);
    				} // if((-1) != iVal)
    			}
    			else
    			{
    				Sleep(100);
    			}
    		}
    		while(true != pclThread->checkThreadStop());
    		pclThread->exitThread();
    	}
    	catch(...)
    	{		
    		debugOut->debug(0,"strTemp erweitert");
    	}
    }
    

  • Mod

    dragonfight86 schrieb:

    Ich finde es mit String einfach

    Aber dein Problem ist doch jetzt, dass die Daten in einem String sind.

    und hatte dazu auch keine Alternative.

    Du brauchst vor die Definition aus der Dokumentation doch fast nur noch " struct Datenpaket { " zu schreiben und hättest dann direkt den passenden Datentyp.



  • Mein Problem ist das ich keine Ahnung habe wie ich diese Daten verarbeiten kann...reicht es wenn ich Sie un ein unsigned short oder uint16 packe ?

    Da kommen mehre Packete an bzw. sind das eher Teilpakete. Ich habe nun vom MagicByte bis zum nächten MagicByte immer in einen String gepackt. Ich weiß nicht ob es sinnvoll ist während des Empfangs die Daten gleich in ein Struct zu packen...



  • Es funktioniert und ich weiß nicht warum 😃 ist das traurig.... was macht die Pipe und die <<8 , kann mir das jemand erklären?

    unsigned short usMagicKey = 0;
    usMagicKey =((strPaket[1] << 8) | strPaket[0]);
    


  • >> und << sind Shift-Operatoren und verschieben die Bits einer Zahl nach rechts bzw nach links. Mathematisch ist das eine Division (bzw. Multiplikation) durch 2n.
    Der | Operator ist eine Oder Verknüpfung zweier Zahlen. Google weiß mehr dazu.



  • Die Pipe als "Oder Operator" kenne ich schon doch sehe ich den Sinn hier nicht in der Anweisung....

    also Ich habe ja mehre Byte sagen wir mal B1 und B2....wenn ich diese jetzt in ein unsigned short packen will muss ich ja erst B2 und dann B1 packen. Also sage ich durch die "<<8" das B2 um 8 bit nach links soll und B1 dann quasi hinten angehängt wird....aber warum steht die Pipe dazwischen ?

    Ich finde dazu leider nur ein haufen Diskusionen die ich aufgrund mangelden Wissens nicht einmal ansatzweise verstehe. Also inhaltlich nicht, die Quellcodes die ich verstehe sind für mich leider auch nochnicht selbst erklärend.

    Ich wäre dir/euch also weirklich sehr dankbar wenn ich auf dem Pfad der Erleuchtung etwas Hilfe bekommen könnte.


  • Mod

    Unter der Annahme, dass chars bei dir 8-Bit haben:

    Nehmen wir mal an, das erste Zeichen in deinem String wäre b10011001 und das zweite Zeichen wäre b10101010. Du möchtest daraus einen unsigned short mit Wert b1001100110101010 machen. Wie machst du das?
    1. Schritt: Du verschiebst den ersten char 8 Zeichen nach rechts, du bekommst b1001100100000000
    2. Schritt: Du verODERst die beiden Werte und bekommst das gewünschte Ergebnis. Prinzipiell ginge auch Addition statt ODER.

    Aber wie ich schon sagte: Lass doch den String einfach ganz weg, du machst dir selber das Leben schwer. Alles was du mit dem String machst, kannst du doch auch direkt mit den Eingangsdaten machen. Mach deine Rechnung, die du hier zeigst, also einfach direkt, wenn du die Daten erhältst.

    Da es hier in diesem Thread speziell um die unterliegende Repräsentation der Daten geht: Wenn die ByteOrder in den Eingangsdaten (du sagst, Little Endian) mit der Byte Order der verarbeitenden Maschine (die meisten Computer benutzen auch Little Endian) überein stimmt, dann kannst du dir auch die ganze Rechnung sparen. Dann sind die Eingangsdaten schließlich schon im passenden Format der Maschine. Wie ich schon sagte, musst du doch praktisch nur noch struct vor deine Dokumentation schreiben und hättest gleich den passenden Datentyp, um die Eingangsdaten damit anzusprechen.



  • zu den String habe ich die Vorgabe bekommen , leider.

    Danke für deine Erklärung das leuchtet jetzt etwas heller bei mir.

    Nochmal zu dem Struct,
    ich sollte also die Daten die in cRecv ankommen nicht in einen String packen sondern in einem char array lassen und diese dann in eine Liste oder Verctor packen.
    Und daraus würde ich dann jeweils das das char[] nehmen und wie dertw dem struct zuweisen ?


Anmelden zum Antworten