C ++에서 ReneterPret_cast <>을 사용하는 문제
-
18-09-2019 - |
문제
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()
) 가상 방법이나 상속을 추가하지 않으면 정상적으로 오버레이됩니다.