LINUX.ORG.RU

[C] выравнивание структур и пересылка по сети

 


0

0

допустим ,есть структура

struct  disconn{
  unsigned char code;
  unsigned char  reason[512];
}
данные надо передать по сети и принять в такую же структуру. причем от строки передается только часть, и размер этой части может меняться(вторая сторона получает размер несколько раньше) но выравнивание может выполняться по-разному, поэтому результат
struct  disconn d;
recv(sock,&d,msg_size,0);
можеть дать несколько иные данные, чем посылались.

какие есть способы избежать данной гадости? я вижу 2: или задавать размеры полей структур такого размера, чтобы выравнивание не случалось нигде, или данные вручную склеивать в массив байт, что приводит к адресной арифметике, а её как раз не хочется. какие еще варианты возможны?


>допустим ,есть структура
struct disconn{
unsigned char code;
unsigned char reason[512];
}

Не совсем понятно о каком выравнивании в данном случае идет речь - зачем выравнивать char ? Или это просто неудачный пример ?

kerosinkin
()
Ответ на: комментарий от kerosinkin

# ./a.out
0xBFBBBDD4, 0xBFBBBDD8, 0xBFBBBDDC, 0xBFBBBDDD
# uname -m
i686
# cat 14.c
#include <stdio.h>

typedef struct  {
    unsigned char code;
    unsigned int  test_int;
    unsigned char test_char;
    unsigned char reason[512];
} disconn;

int main(void) 
{
    disconn d;

    printf("0x%X, 0x%X, 0x%X, 0x%X\n", (unsigned int)&d.code, (unsigned int)&d.test_int, (unsigned int)&d.test_char, (unsigned int)&d.reason);

    return 0;
}

# ./a.out                                                                       
0xBEC4BB34, 0xBEC4BB38, 0xBEC4BB3C, 0xBEC4BB3D                                  
# uname -m                                                                      
armv5tejl
как видишь выравнивание сделано для int и не нужно для char, доступ к байту и слову - это разные опкоды.

kerosinkin
()

int Assemble(char *buf, int bufLen, const char *format, ...)
{
	va_list ap;
	va_start(ap, format);
	int len = VAssemble(buf, bufLen, format, ap);
	va_end(ap);
	return len;
}

const char *StrNChr(const char *str, char c, int len)
{
	while (len > 0)
	{
		if (*str == c)
			return str;

		str++;
		len--;
	}
	return str;
}

int WcsNLen(const unsigned char *str, int len)
{
	int i = 0;
	
	for (; i < len; i++)
	{
		if (!str[0] && !str[1])
			break;

		str += 2;
	}
	return i;
}

//XXXTODO: use VDisassemble
const unsigned char *Disassemble(const unsigned char* packet, const char* format, ...)
{
	//const char* f = format;
	va_list ap;
	int t;
	va_start(ap, format);
	while ((t = *format++))
	{
		switch (t)
		{
		case 'c':
			{
				char* cp = va_arg(ap, char*);
				*cp = *packet++;
			}
			break;
		case 'h':
			{
				short* hp = va_arg(ap, short*);
				*hp = ((short *)packet)[0];
				packet += 2;
			}
			break;
		case 'd':
			{
				int* dp = va_arg(ap, int*);
				*dp = ((int *)packet)[0];
				packet += 4;
			}
			break;
		case 'f':
			{
				double* dp = va_arg(ap, double*);
				CopyMemory(dp, packet, 8);
				packet += 8;
			}
			break;
    case 'b': //blind copy
      {
        int dstLen = va_arg(ap, int);
        char* dst = va_arg(ap, char*);
        memcpy(dst,(char*)packet,dstLen);
        packet += dstLen;
      }
      break;
		case 's':
			{
				int dstLen = va_arg(ap, int);
				char* dst = va_arg(ap, char*);
				strncpy(dst, (char*)packet, dstLen);
				dst[dstLen - 1] = 0;
				unsigned char* end = (unsigned char*)StrNChr((char*)packet, '\0', dstLen) + 1;
				packet = end;
			}
			break;
		case 'S':
			{
				int len = va_arg(ap, int) / sizeof(wchar_t);
				len = WcsNLen(packet, len-1);
				wchar_t* dst = va_arg(ap, wchar_t*);
				memcpy(dst, packet, len * sizeof(wchar_t));
				dst[len] = 0;
				packet += (len + 1) * sizeof(wchar_t);
			}
			break;
		default:
      break;
		}
	}
	va_end(ap);

	return packet;
}

int VAssemble(char* buf, int bufLen, const char* format, va_list ap)
{
//	const char* f = format;
	char* start = buf;
	char* end = buf + bufLen;
	int t;
	char* p;
	size_t len;
	int i;

	double d;

	while ((t = *format++))
	{
		switch (t)
		{
		case 's':
			p = va_arg(ap, char*);
			if (p)
			{
				len = strlen(p);
				if (buf + len + 1 > end)
				{
					goto overflow;
				}
				strcpy(buf, p);
				buf += len + 1;
			}
			else
			{
				if (buf + 1 > end)
				{
					goto overflow;
				}
				*buf++ = 0;
			}
			break;
#ifdef WIN32
		case 'S': 
			{
				wchar_t* p = va_arg(ap, wchar_t*);
				if (p)
				{
					len = (wcslen(p) + 1)* sizeof(wchar_t);
					if (buf + len > end)
					{
						goto overflow;
					}
					memcpy(buf, p, len);
					buf += len;
				}
				else
				{
					if (buf + 2 > end)
					{
						goto overflow;
					}
					*buf++ = 0;
					*buf++ = 0;
				}
			}
			break;
#endif
		case 'b':
			len = va_arg(ap, int);
			p = va_arg(ap, char*);
			if (buf + len > end)
			{
				goto overflow;
			}
			memcpy(buf, p, len);
			buf += len;
			break;
		case 'c':
			i = va_arg(ap, int);
			if (buf + 1 > end)
			{
				goto overflow;
			}
			*buf++ = i;
			break;
		case 'h':
			i = va_arg(ap, int);
			if (buf + 2 > end)
			{
				goto overflow;
			}
			*((short *)buf) = i;
			buf += 2;
			break;
		case 'd':
			i = va_arg(ap, int);
			if (buf + 4 > end)
			{
				goto overflow;
			}
			*((int *)buf) = i;
			buf += 4;
			break;

		case 'f':
			d = va_arg(ap, double);
			if (buf + 8 > end)
			{
				goto overflow;
			}
			CopyMemory(buf, &d, 8);
			buf += 8;
			break;

		}
	}
	return (int)(buf - start);
overflow:
  ASSERT(FALSE); //XXXTODO: gayish crap ~.~
	return 0;
}

==============================================================
char packet[1024] = {};
int nSize = 0;
disconn crap;

nSize = Assemble(packet,1024,"b",sizeof(disconn),&crap);
bufferevent_write(evt, packet, nSize);


nikolayd
()

Я не видел еще ни одного проекта где бы для таких целей не использовалась бы сериализация. Шаманство с выравниванием - это полная хрень + ты забываешь заодно о порядке байт. Хотя, если ты планируешь запускать клиента и сервера, скомпиленных идентичными компиляторами с идентичными параметрами на идентичных машинах, и при этом готов обеспечить себе сопутствующий геморрой в будущем при развитии проекта - тогда можешь пойти по озвученному тобой пути №1.

mannaz
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.