문제

Datastream이 고정형 메시지로 구성되며 각 메시지는 정의 된 고정 너비 필드도 FULLE를 갖기 때문에 Datastream을 구조물로 캐스팅하려고합니다. 구조물을 만들고 RenterPret_cast를 사용하여 Datastream에 대한 포인터를 구조물에 캐스트하여 필드를 얻을 계획이었습니다. 나는 약간의 테스트 코드를 만들고 이상한 결과를 얻었습니다. 내가 왜 이것을 얻는 지 또는 코드를 수정하는 방법을 설명 할 수 있습니다. (Datastream은 바이너리 및 알파 숫자 혼합이지만 스트링으로 단지 테스트합니다)

#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;
}

출시 될 결과가 있습니다

4
four
our
ur
r

나는 네, 우리와 Ur가 널 터미네이터를 찾을 수 없기 때문에 인쇄한다고 생각합니다. NULL 터미네이터 문제를 어떻게 해결합니까?

도움이 되었습니까?

해결책

숯의 배열을 인쇄하고 널 말하는 문자열과 구별 할 수 있으려면 다른 사람이 필요합니다. 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;
}

다른 팁

당신은 null 터미네이터의 부족에 대해 옳습니다. "ur"을 다시 인쇄하는 이유는 헤더-> 네 번째 대신 헤더> 세 번째를 반복했기 때문입니다. "char [1]대신에 변수를 "char"로 선언하지 않겠습니까?

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

문제는 재 해석 _cast가 아니라 (사용하는 것은 매우 나쁜 생각이지만) 구조물의 것들에 있습니다. 그들은 'char [1]'형이 아닌 'char'형이어야합니다.

#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;
}

내 경험상 사용 #pragma pack 두통이 발생했습니다. 부분적으로는 올바르게 팝되지 않는 컴파일러로 인해 한 헤더에서 팝을 잊어 버리는 개발자로 인해 발생했습니다. 그와 같은 실수와 구조는 결국 어느 것에 따라 다르게 정의되었습니다. 주문하다 헤더는 컴파일 장치에 포함됩니다. 디버깅 악몽입니다.

나는 그런 이유로 메모리 오버레이를하지 않으려 고 노력합니다. 당신은 당신의 구조물이 당신이 기대하는 데이터와 올바르게 정렬되어 있음을 믿을 수 없습니다. 대신, 나는 "기본"C ++ 형식의 메시지의 데이터를 포함하는 structs (또는 클래스)를 만듭니다. 예를 들어, 정렬 목적으로 만있는 경우 정의 된 "필러"필드가 필요하지 않습니다. 그리고 아마도 필드의 유형이 int 그것보다 char[4]. 가능한 빨리 데이터를 "기본"유형으로 변환하십시오.

Alexey 코드의 사본을 피하기 때문에 오버레이 가능한 구조물을 계속 사용하고 싶다고 가정하면 Raw Char 어레이를 다음과 같은 래퍼로 교체 할 수 있습니다.

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;
}

그러면 생성 된 구조는 다음과 같습니다.

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

기존 코드는 제대로 작동해야합니다.

NB. 원하는 경우 고정 스트에 메소드를 추가 할 수 있습니다 (예 : std::string FixedStr::toString()) 가상 방법이나 상속을 추가하지 않으면 정상적으로 오버레이됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top