2009-11-09 14 views
9

Chcę przesłać dane przez sieć, ale nie chcę używać żadnych bibliotek zagranicznych (Standard C/C++ jest ok).Serializuj łańcuchy znaków, int i float do tablic znaków w celu tworzenia sieci BEZ BIBLIOTEK

na przykład:

unsigned int x = 123; 
char y[3] = {'h', 'i', '\0'}; 
float z = 1.23f; 

chcę to w

char xyz[11]; 

tablicy.

Uwaga: Aby przesłać go przez sieć, potrzebuję zamówienia Bajt sieci dla niepodpisanego int (funkcja htonl), to muszę jakoś serializować float, aby był w formularzu IEEE 754 (tam jest wiele funkcji w Internecie), i wiem to.

Jak mogę je wprowadzić do tablicy Xyz, ładnie ustawionej w linii koniec do końca, więc mogę użyć tego jako bufora dla funkcji socket + send()? Oczywiście mam funkcje odwróconych (ntohl i wsteczny IEEE 754), aby się ich pozbyć, ale muszę technikę tam też, korzystnie takie same ...

To byłoby coś takiego:

 
xyz in binary: 
00000000 0000000 00000000 01111011 | 01101000 | 01101001 | 00000000 | 00111111 10011101 01110000 10100100 
- big endian repr. of u. int 123 - | - 'h' - | - 'i' - | - '\0' - | - IEEE 754 repr of float 1.23 - 

Jak mogę to zrobić bez zewnętrznych bibliotek i minimalnego wykorzystania standardowych funkcji bibliotecznych? Nie jest to tak ważne dla mojego programu, jak i dla mnie.

+0

Po pierwsze, w rzeczywistości nie zadeklarowano żadnej zmiennej y. Czy to tablica znaków? Czy wiesz, jak duże są te tablice, czy są dynamiczne? –

+0

Przykro mi, oczywiście nie mogę zainicjować y z literałem łańcuchowym w podwójnych cudzysłowach, naprawiłem to. Ma 3 bajty. – wsd

Odpowiedz

16

Ach, chcesz serializacji prymitywne typy danych!Zasadniczo istnieją dwa podejścia: Po pierwsze, chwytasz wewnętrzną, binarną reprezentację danych, które chcesz serializować, ponownie interpretujesz jako znak i używasz go jako reprezentacji:

Więc jeśli masz:

podwójne d;

wziąć adresu tego, reinterpretacji tego wskaźnika jako wskaźnik do znaku, a następnie wykorzystać te znaki:

double *pd=&d; 
char *pc = reinterpret_cast<char*>(pd); 
for(size_t i=0; i<sizeof(double); i++) 
{ 
    char ch = *pc; 
    DoSomethingWith(ch); 
    pc++; 
} 

ten działa ze wszystkimi prymitywnych typów danych. Głównym problemem jest to, że reprezentacja binray jest zależna od implementacji (głównie zależy od procesora). (I natkniesz się na subtelne błędy, gdy spróbujesz to zrobić z IEEE NAN ...).

Podsumowując, takie podejście w ogóle nie jest przenośne, ponieważ nie masz żadnej kontroli nad reprezentacją danych.

Drugie podejście polega na użyciu reprezentacji wyższego poziomu, którą sam kontrolujesz. Jeśli wydajność nie jest problemem, możesz użyć operatorów std :: strstream i >> i < <, aby przesyłać prymitywne zmienne typu C do std :: string. Jest to powolne, ale łatwe do odczytania i debugowania i bardzo przenośne.

+0

+1 do podświetlania problemów i dodawania niezdefiniowanego dopełnienia. I ugryzę bate :), jakie są subtelne błędy z IEEE NaN w tym scenariuszu? Dzięki .. –

+1

Istnieją sygnalizujące NaN i nienazwane NaN. Kiedy pracujesz z tymi reprezentacjami jako tablice char, możesz je łatwo odczytać i zapisać. Ale kiedy uzyskujesz dostęp do nich jako zmiennoprzecinkowe, sam akt ich czytania może spowodować sygnalizację przez procesor. Więc jeśli nie jesteś ostrożny, możesz skończyć z programem, który deserializuje się bez problemu, ale kiedy dotkniesz pływaka, skończysz z kłopotami. A ponieważ ten wątek dotyczy nauki, pomyślałem, że mogę wskazać ten obszar. –

+0

+1, i nie widziałem tego w tym kontekście wymienionego tutaj .. chociaż sprzedawcy unikają rozrządzania, a także szeregowania wszelkiego rodzaju pływaków, wreszcie :) –

0

Jaki jest dokładnie Twój cel? I do czego dokładnie służą środki, z których chcesz skorzystać?

Jeśli chcesz wykonać zadanie za pomocą jednego konkretnego kompilatora na jednym komputerze, to najszybszym i najprostszym, ale także najbrudniejszym rozwiązaniem jest użycie unii. Definiujesz strukturę, która ma twoje elementy jako członków i łączy je z tablicą znaków. Musisz powiedzieć kompilatorowi, żeby naprawdę mocno spakował członków, coś podobnego do #pragma pack (1), a twój problem został rozwiązany. Po prostu przechowujesz trzy wartości w elementach, a następnie traktujesz je jako tablicę znaków.

Jeśli maszyna jest trochę endianowa i potrzebujesz dużych endianów/float, po prostu zamieniasz odpowiednie znaki.

Ale istnieją co najmniej kolejne rozwiązania, które przychodzą na myśl, jeśli masz inne cele, takie jak przenośność, niestandardowa kolejność bajtów, sizeof (int)! 4, float nie są przechowywane wewnętrznie w formacie IEEE, itp.

+0

Chcę nauczyć się serializować prymitywne typy danych C/C++ (w taki sposób, żebym mógł dodać wiedzę o późniejszych serializacjach) w C/C++. Środkami są wszelkie funkcje C/C++ akceptowane przez GCC i funkcje standardowej biblioteki C/C++. Dziękuję, zajrzę do związków. – wsd

8

Coś jak poniższy kod to zrobi. Uważaj na problemy, w których sizeof (unsigned int) jest różny w różnych systemach, to dostaniesz. W takich sytuacjach lepiej używać typów o ściśle określonych rozmiarach, takich jak int32_t. W każdym razie ...

unsigned int x = 123; 
char y[3] = {'h', 'i', '\0'}; 
float z = 1.23f; 

// The buffer we will be writing bytes into 
unsigned char outBuf[sizeof(x)+sizeof(y)+sizeof(z)]; 

// A pointer we will advance whenever we write data 
unsigned char * p = outBuf; 

// Serialize "x" into outBuf 
unsigned int32_t neX = htonl(x); 
memcpy(p, &neX, sizeof(neX)); 
p += sizeof(neX); 

// Serialize "y" into outBuf 
memcpy(p, y, sizeof(y)); 
p += sizeof(y); 

// Serialize "z" into outBuf 
int32_t neZ = htonl(*(reinterpret_cast<int32_t *>(&z))); 
memcpy(p, &neZ, sizeof(neZ)); 
p += sizeof(neZ); 

int resultCode = send(mySocket, outBuf, p-outBuf, 0); 
[...] 

... i oczywiście kod odbiorczy zrobiłby coś podobnego, z wyjątkiem odwrotnym.

1

Ten discussion wydaje pasuje do Twojego pytania, ale korzysta pobudzenia serializacji API

+0

Myślę, że Boost wiele Cię nauczy (możesz sprawdzić implementację). A także da ci gotowe rozwiązanie wielu problemów, których nie możesz sam sobie wyobrazić. –

+0

Przeglądam interfejs API Boost Serialization, kiedy to piszę (w innej karcie xD), ale wydaje mi się, że jest to przesada w stosunku do tego, co chcę zrobić. Próba programowego destylowania ... – wsd

Powiązane problemy