Каждая переменная существует в памяти вашего компьютера. Память организована в байтах.
Когда вы пишете код C++, вы можете напрямую читать эти байты. Для структуры память для всех ее элементов находится в одном непрерывном блоке (хотя между каждым элементом могут быть промежутки).
Итак, если я объявлю:
struct foo {
char x;
char y;
short z;
int q;
};
Затем, когда я создаю struct foo
, я получаю в памяти следующий макет (всего 8 байтов в большинстве систем):
xyzzqqqq
Первый байт — x
, второй — y
, третий и четвертый вместе — z
, а последние четыре — q
.
Итак, объект уже "сериализован" - у вас есть куча байтов, которые его представляют. Это все, что вам нужно отправить по сети: информацию, которая представляет структуру данных.
Причина, по которой вы написали бы свой собственный сериализатор, заключается в том, что вы можете захотеть изменить способ чтения или записи объекта (например, что, если бы я добавил поле к struct foo
?), потому что вам нужно для связи между машинами, где расположение памяти отличается (какой байт z
представляет «самую значащую» часть числа?), или потому что вы хотите сериализовать только часть структуры (что, если бы у нас было пустое пространство между членами ?).
Но, по сути, причина, по которой вы отправляете «char data», заключается в том, что все на вашем компьютере может быть представлено таким образом. Я не буду вдаваться в доказательства Тьюринга о кодировании символов, но это математическая уверенность в том, что любое знание может быть закодировано как последовательность единиц и нулей.
Говоря более конкретно, способ, которым вы помещаете данные в поле «char data» пакета, — это memcpy
ing из того места, где данные в данный момент находятся в буфере. Итак, если бы у меня было char* target
, я мог бы записать в него struct foo x
таким образом:
memcpy(target, &x, sizeof(struct foo));
Или я мог бы сделать это более тщательно, написав каждое поле:
memcpy(target, &x.x, 1);
memcpy(target+1, &x.y, 1);
memcpy(target+2, &x.z, sizeof(short));
memcpy(target+4, &x.q, sizeof(int));
&
— это адрес оператора, если вы еще не знали. Итак, я пишу с адреса каждого члена по некоторому смещению в пределах target
и записываю количество байтов, равное длине представления переменной члена.
В принятом ответе на ваш последний вопрос указано, что это чрезмерное упрощение: когда вы отправляете многобайтовое целое число по сети, вам нужно беспокоиться о порядке байтов (порядке байтов). Итак, что вы на самом деле делаете, это:
memcpy(target, &x.x, 1);
memcpy(target+1, &x.y, 1);
*((short*)(target+2)) = htons(x.z);
*((int*)(target+4)) = htonl(x.q);
Это обработает изменение байтов соответствующим образом для преобразования узлового порядка байтов в сетевой порядок байтов. Очевидно, что однобайтовые значения невосприимчивы.
person
Borealid
schedule
16.02.2012