سؤال

أحاول إرسال دفق بيانات إلى بنية نظرًا لأن دفق البيانات يتكون من رسائل ذات عرض ثابت وكل رسالة تحتوي على حقول عرض ثابتة محددة تمامًا أيضًا.كنت أخطط لإنشاء بنية ثم استخدام reinterpret_cast لإرسال المؤشر إلى تدفق البيانات إلى البنية للحصول على الحقول.لقد قمت بعمل بعض رموز الاختبار وحصلت على نتائج غريبة.هل يمكن لأي شخص أن يشرح سبب حصولي على هذه الأشياء أو كيفية تصحيح الكود.(سيكون تدفق البيانات مختلطًا بالأرقام الثنائية والأبجدية ولكني أقوم فقط بالاختبار باستخدام السلاسل)

#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 تتم طباعتهم نظرًا لعدم تمكنهم من العثور على أداة الإنهاء الفارغة.كيف أتغلب على مشكلة الإنهاء الفارغ؟

هل كانت مفيدة؟

المحلول

من أجل أن تكون قادرا على طباعة مجموعة من الأحفير، والقدرة على التمييز بينها من سلسلة غير ذات النهاية، تحتاج إلى أخرى 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;
}

نصائح أخرى

أنت على حق في عدم وجود المنهي الخالي. السبب في طباعة "UR" مرة أخرى لأنك تكررت الرأس الواحد - الثالث بدلا من رأسه الرابع. بدلا من "Char [1]، لماذا لا تعلن فقط هذه المتغيرات بأنها "شار"؟

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

المشكلة ليست إعادة تتريت (على الرغم من استخدامها فكرة سيئة للغاية) ولكن في أنواع الأشياء في الهيكل. يجب أن يكونوا من نوع "char"، وليس من النوع "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;
}

في تجربتي، باستخدام #pragma pack تسبب في حدوث صداع - ويرجع ذلك جزئيًا إلى عدم ظهور المترجم بشكل صحيح، ولكن أيضًا بسبب نسيان المطورين للظهور في رأس واحد.خطأ واحد من هذا القبيل والبنيات ينتهي بها الأمر إلى تعريفها بشكل مختلف اعتمادًا على أي منها طلب يتم تضمين الرؤوس في وحدة التجميع.إنه كابوس التصحيح.

أحاول عدم القيام بتراكبات الذاكرة لهذا السبب - لا يمكنك الوثوق في أن البنية الخاصة بك تتماشى بشكل صحيح مع البيانات التي تتوقعها.وبدلاً من ذلك، أقوم بإنشاء بنيات (أو فئات) تحتوي على البيانات من رسالة بتنسيق C++ "أصلي".على سبيل المثال، لا تحتاج إلى تحديد حقل "الحشو" إذا كان موجودًا فقط لأغراض المحاذاة.وربما يكون من المنطقي أكثر أن يكون نوع الحقل int من أن يكون char[4].في أقرب وقت ممكن، قم بترجمة تدفق البيانات إلى النوع "الأصلي".

على افتراض أنك تريد الاستمرار في استخدام بنية محطيرة (وهو أمر معقول، نظرا لأنه يتجنب النسخة في رمز Alexey)، يمكنك استبدال صفائف Char RAW مع غلاف مثل ما يلي:

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

وعلى الكود الموجود الخاص بك يجب أن يعمل بشكل جيد.

ملحوظة يمكنك إضافة طرق إلى Dixstr إذا كنت تريد (على سبيل المثال، std::string FixedStr::toString()) فقط لا تضيف الأساليب الافتراضية أو الميراث، وسوف يتراكم بشكل جيد.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top