Analizando datos en struct

Estoy trabajando en un proyecto donde necesito comunicarme con un dispositivo a través del protocolo TCP / IP. El dispositivo envía una gran cantidad de datos que de alguna manera quiero analizar en algunos objects / estructuras.

Ejemplo del formatting de datos (en el búfer TCP []):

[64] [1] [78] [244] [77] [189] [249] [149] hcurrent [64] [1] [78] [247] [89] [95] [104] [85] htarget [0] [0] [0] [0] [0] [0] [0] [0] qcurrent [188] [220] [97] [3] [66] [62] [0] [0] kcurrent [66] [0] [102] [103] [66] [99][153] [154] mcurrent [253] [191] [246] [74] [170] [216] [242] [29] fmode [102] [191] [246] [74] [178] [44] [92] [72] tmil [137] mode 

Ahora este marco de package se identifica como:

  double hcurrent double htarget double qcurrent float kcurrent float mcurrent float fmode float tmil unsigned char mode 

Mi idea era que, de algún modo, podía analizar los datos directamente en una estructura que tuviera la misma estructura que la anterior. Por supuesto, será necesario identificar algunos valores key para determinar qué tipo de datos es.

¿Cómo se puede hacer esto?

Como estoy codificando para un dispositivo iOS, tiene que ser objective-C o C (++).

EDIT (método probado para copyr cada parte del datagtwig en struct): implementación Java pequeña donde bash leer los primeros 4 bytes [0] [0] [1] [5] :

 byte[] read = new byte[4]; int length = 0; while (length < read.length) { len = iStream.read(read, len, read.length); } int ByteLength = (int)unsignedIntToLong(read); ByteLength = ByteLength-5; state = 1; // Continue and work with next data. 

Y el método de manipulación de bits:

 public long unsignedIntToLong(byte[] b) { long l = 0; l |= b[0] & 0xFF; l <<= 8; l |= b[1] & 0xFF; l <<= 8; l |= b[2] & 0xFF; l <<= 8; l |= b[3] & 0xFF; return l; } 

Así que busco los primeros 4 bytes que mencioné anteriormente, que determina algo específico y, al final, encuentro la longitud de 465 . Mi plan es repetir este process con todas las demás partes de los datos recibidos.

El mayor problema que tendrás es que las estructuras no almacenan datos de forma completamente contigua, alinean los datos según los límites de las palabras

Esto significa que no puede simplemente definir una estructura y luego lanzar su búfer [] a ella si el búfer no contiene una estructura para comenzar. En su lugar, lo que probablemente deba hacer es declarar un struct y luego memcpy cada parte del buffer [] en un campo a la vez usando apointer offset en el buffer [].

Si este enfoque es demasiado engorroso, a menudo es posible desactivar la alignment de la estructura para que una estructura pueda representar datos completamente empaquetados. MSVC permite el uso del package #pragma para hacer esto. Sin embargo, este enfoque ralentiza el acceso a la memory de la estructura.

EDIT: Aquí hay un ejemplo que muestra cómo puede usar una function de plantilla para leer cualquier tipo de un búfer y luego actualizar un desplazamiento en ese búfer. Puede usar este método para analizar de forma segura cualquier número de types en una estructura, uno por uno:

 // We want to copy raw data to this structure // but the short will cause it to be unaligned struct _parsed_structure { int a; int b; short c; int d; } parsed_structure; template<typename T> void read_and_update_offset (int & offset, char * buffer, T & var) { T * pInt = (T*)(buffer + offset); var = *pInt; offset += sizeof(T); }; int _tmain(int argc, _TCHAR* argv[]) { // Here's a buffer which we know contains ints and shorts, we could just cast it to our structure // but this will cause errors because the structure will not be aligned properly. char buffer[] = { 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 4, 0, 0, 0 }; // Read the first int from the buffer into the structure int offset = 0; read_and_update_offset(offset, buffer, parsed_structure.a); read_and_update_offset(offset, buffer, parsed_structure.b); read_and_update_offset(offset, buffer, parsed_structure.c); read_and_update_offset(offset, buffer, parsed_structure.d); // Print the values std::cout << parsed_structure.a << " " << parsed_structure.b << " " << parsed_structure.c << " " << parsed_structure.d << " " << std::endl; // Look the size of our structure is different than the size of our buffer due to alignment std::cout << "sizeof(buffer)" << "==" << sizeof(buffer) << " " << "sizeof(parsed_structure)" << "==" << sizeof(parsed_structure) << std::endl; return 0; } 

El enfoque usual para algo así es escribir methods nextInt , nextDouble , etc. que leerán bytes de la secuencia (en el order "endian" apropiado) y devolverán un valor del tipo indicado, actualizando un puntero o índice en la matriz, ya que hacer. Esto es mucho más manejable que intentar alinear las conversiones, y puede ser bastante eficiente. (Puede hacer que los methods C ++ vs Objective-C sean eficientes).