Pregunta

Estoy intentando emitir una corriente de datos en una estructura desde la corriente de datos consiste en mensajes de ancho fijo y cada mensaje tiene Fulle definido campos de ancho fijo también. Yo estaba pensando en la creación de una estructura y luego usando reinterpret_cast para emitir puntero al flujo de datos a la estructura para obtener los campos. Hice un poco de código de prueba y obtener resultados extraños. Podría alguno explicar por qué estoy recibiendo estos o cómo corregir el código. (La corriente de datos va a ser binarios y alfa numérico mezclada pero im apenas probando con cuerdas)

#pragma pack(push,1)
struct Header 
{
    char msgType[1];
    char filler[1];
    char third[1];
    char fourth[1];
};
#pragma pack(pop)

int main(void)
{
    cout << sizeof(Header) << endl;

    char* data = "four";
    Header* header = reinterpret_cast<Header*>(data);
    cout << header->msgType << endl;
    cout << header ->filler << endl;
    cout << header->third << endl;
    cout << header->fourth << endl;
    return 0;
}

El resultado que están surgiendo son

4
four
our
ur
r

Creo que los cuatro, y nuestra ur es la impresión, ya que no puede encontrar el terminador nulo. ¿Cómo llego en torno al tema terminador nulo?

¿Fue útil?

Solución

Con el fin de ser capaz de imprimir una gran variedad de caracteres, y ser capaz de distinguirla de una cadena terminada en cero, necesita otras definiciones operator<<:

template< size_t N >
std::ostream& operator<<( std::ostream& out, char (&array)[N] ) {
     for( size_t i = 0; i != N; ++i ) out << array[i];
     return out;
}

Otros consejos

Tiene razón de la falta de terminador nulo. La razón es la impresión "ur" de nuevo se debe a que repitieron el Header> tercer lugar de Header> cuarto. En lugar de "char [1]", ¿por qué no declarar las variables como "char"?

struct Header 
{
    char msgType;
    char filler;
    char third;
    char fourth;
};

El problema no se reinterpret_cast (aunque su uso es una muy mala idea), pero en los tipos de las cosas en la estructura. Deben ser de tipo "char, no de tipo 'char [1]'.

#pragma pack(push,1)
template<int N>
struct THeader 
{
    char msgType[1+N];
    char filler[1+N];
    char third[1+N];
    char fourth[1+N];
};
typedef THeader<0> Header0;
typedef THeader<1> Header1;  
Header1 Convert(const Header0 & h0) {
   Header1  h1 = {0};
   std::copy(h0.msgType, h0.msgType + sizeof(h0.msgType)/sizeof(h0.msgType[0]), h1.msgType);
   std::copy(h0.filler, h0.filler+ sizeof(h0.filler)/sizeof(h0.filler[0]), h1.filler);
   std::copy(h0.third , h0.third + sizeof(h0.third) /sizeof(h0.third [0]), h1.third);
   std::copy(h0.fourth, h0.fourth+ sizeof(h0.fourth)/sizeof(h0.fourth[0]), h1.fourth);
   return h1;
}
#pragma pack(pop)


int main(void)
{
  cout << sizeof(Header) << endl;
  char* data = "four";
  Header0* header0 = reinterpret_cast<Header*>(data);
  Header1 header = Convert(*header0);
  cout << header.msgType << endl;
  cout << header.filler << endl;
  cout << header.third << endl;
  cout << header.fourth << endl;
  return 0;
}

En mi experiencia, el uso de #pragma pack ha causado dolores de cabeza - en parte debido a un compilador que no salga correctamente, pero también debido a los desarrolladores de olvidarse de hacer estallar en un encabezado. Un error como ese y estructuras terminan definido de manera diferente dependiendo de la Para cabeceras ser incluido en una unidad de compilación. Es una pesadilla depuración.

Trato de no hacer superposiciones de memoria por esa razón - no se puede confiar en que su estructura está correctamente alineado con los datos que está esperando. En su lugar, se crea estructuras (o clases) que contienen los datos de un mensaje en un formato "nativo" C ++. Por ejemplo, no es necesario un campo de "relleno" define si es sólo allí para fines de alineación. Y tal vez tiene más sentido para el tipo de un campo para ser int que para que sea char[4]. Tan pronto como sea posible, traducir el flujo de datos en el tipo "nativo".

Si se asume que desea seguir usando una estructura overlayable (que es sensible, ya que evita la copia en el código de Alexey), puede reemplazar las matrices de char primas con un envoltorio como el siguiente:

template <int N> struct FixedStr {
    char v[N];
};

template <int N>
std::ostream& operator<<( std::ostream& out, FixedStr const &str) {
    char const *nul = (char const *)memchr(str.v, 0, N);
    int n = (nul == NULL) ? N : nul-str.v;
    out.write(str.v, n);
    return out;
}

A continuación, sus estructuras generadas se verá como:

struct Header 
{
    FixedStr<1> msgType;
    FixedStr<1> filler;
    FixedStr<1> third;
    FixedStr<40> forty;
};

y su código existente debería funcionar bien.

NB. puede agregar métodos para FixedStr si lo desea (por ejemplo, std::string FixedStr::toString()) simplemente no cuadran métodos virtuales o herencia, y va a superponer bien.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top