ما هو بالضبط خطر استخدام قيم التصحيح السحرية (مثل 0xDeadbeef) كحرفية؟

StackOverflow https://stackoverflow.com/questions/1681144

سؤال

وغني عن القول أن استخدام المؤشرات الحرفية الصلبة المشفرة، هي كارثة:

int *i = 0xDEADBEEF;
// god knows if that location is available

ومع ذلك، ما هو بالضبط الخطر في استخدام Hex Earptals كمتغير القيم?

int i = 0xDEADBEEF;
// what can go wrong?

إذا كانت هذه القيم "خطيرة" بالفعل بسبب استخدام في مختلف سيناريوهات التصحيح, ، فهذا يعني أنه حتى لو كنت لا نستخدم هذه الحرفية، فإن أي برنامج يحدث أثناء وقت التشغيل يحدث أن تتعثر عند إحدى هذه القيم قد تعطل.

أي شخص يهتم بشرح المخاطر الحقيقية لاستخدام حرف العزف؟


يحرر: فقط للتوضيح، أنا لا أشير إلى الاستخدام العام للثوابت في التعليمات البرمجية المصدرية. أنا أتحدث على وجه التحديد عن مشاكل سيناريو تصحيح قد يصل إلى استخدام قيم Hex، مع مثال محدد ل 0xDEADBEEF.

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

المحلول

أعتقد أن القلق الذي أثير في عنوان تنسيق عنوان الملكية الفكرية في وقت سابق اليوم لا يرتبط باستخدام حرفي عرافة بشكل عام، ولكن الاستخدام المحدد ل 0xDeadbeef. على الأقل، هذه هي الطريقة التي قرأتها بها.

هناك اهتمام باستخدام 0xDeadbeef على وجه الخصوص، على الرغم من أنه في رأيي هو واحد صغير. المشكلة هي أن العديد من المصحوال وأنظمة وقت التشغيل قد اشتغلت بالفعل هذه القيمة الخاصة كقيمة علامة للإشارة إلى كومة غير مقلقة، مؤشرات سيئة على المكدس، إلخ.

لا أتذكر قبالة رأس رأسي، ما هي أنظمة تصحيح الأخطاء والوقت تستخدم هذه القيمة الخاصة، لكنني رأيت ذلك استخدمت بهذه الطريقة عدة مرات على مر السنين. إذا كنت تقوم بتصحيح الأخطاء في إحدى هذه البيئات، فإن وجود ثابت 0xDeadbeef في التعليمات البرمجية سيكون لا يمكن تمييزه عن القيم في ذاكرة الوصول العشوائي غير المخصصة أو أيا كان، لذلك في أفضل الأحوال، لن يكون لديك مقالب RAM مفيدة، وفي أسوأ الأحوال، ستحصل على تحذيرات من المصحح.

على أي حال، هذا ما أعتقد أن المعلق الأصلي يعني عندما أخبرك أنه كان سيئا "للاستخدام في مختلف سيناريوهات التصحيح".

نصائح أخرى

لا يوجد خطر في استخدام عرافة حرفية من أي نوع آخر من حرفي.

إذا كانت جلسة تصحيح الأخطاء تنفذ بيانات تنفيذ كود بدون كود بدونك تنويه، فأنت في عالم من الألم على أي حال.

بالطبع، هناك "القيمة السحرية" العادية "قضية الرموز / النظافة المسماة، ولكن هذا ليس حقا نوع الخطر الذي أعتقد أنك تتحدث عنه.

مع استثناءات قليلة، لا شيء "ثابت".

نحن نفضل الاتصال بهم "المتغيرات البطيئة" - تغييرات القيمة الخاصة بهم ببطء شديد أننا لا تمانع في إعادة ترجمة لتغييرها.

ومع ذلك، لا نريد الحصول على العديد من مثيلات 0x07 جميعا من خلال تطبيق أو برنامج نصي اختبار، حيث يحتوي كل مثيل معنى مختلف.

نريد وضع علامة على كل ثابت يجعله لا لبس فيه تماما ما يعنيه.

if( x == 7 )

ماذا يعني "7" في البيان أعلاه؟ هل هو نفس الشيء كما

d = y / 7;

هل هذا هو نفس معنى "7"؟

حالات الاختبار هي مشكلة مختلفة قليلا. لا نحتاج إلى إدارة واسعة ومتحلة لكل حالة من حرفي رقمي. بدلا من ذلك، نحن بحاجة إلى وثائق.

يمكننا - إلى حد ما - شرح حيث يأتي "7" من خلال إدراج بت صغير من التلميح في التعليمات البرمجية.

assertEquals( 7, someFunction(3,4), "Expected 7, see paragraph 7 of use case 7" );

يجب أن يتم ذكر "ثابت" - ويسمى - مرة واحدة بالضبط.

"النتيجة" في اختبار الوحدة ليست هي نفس الشيء كمثابت، ويتطلب الرعاية القليل في شرح المكان الذي جاء منه.

لا يختلف حرف عرافة أقل من حرفي عشري مثل 1. أي أهمية خاصة للقيمة ترجع إلى سياق برنامج معين.

لا يوجد سبب لماذا يجب أن لا تعين 0xdeadbeef إلى متغير.

لكن Woe Betide the Programmer الذي يحاول تعيين عشري 3735928559, أو Octal. 33653337357, ، أو الأسوأ من الجميع: ثنائي 11011110101011011011111011101111.

الإندان الكبير أو الإندان الصغير؟

خطر واحد هو عندما يتم تعيين الثوابت بمجموعة أو هيكل مع أعضاء مختلفين مختلفين؛ ال الإندانسيؤثر برنامج التحويل البرمجي أو الجهاز (بما في ذلك JVM VS CLR) على ترتيب البايتات.

هذه المشكلة صحيحة للقيم غير الثابتة أيضا، بالطبع.

ها هي، مفتعلة من المسلم بها، مثال. ما هي قيمة مخزن مؤقت [0 بعد السطر الأخير؟

const int TEST[] = { 0x01BADA55,  0xDEADBEEF };
char buffer[BUFSZ];

memcpy( buffer, (void*)TEST, sizeof(TEST));

لا أرى أي مشكلة في استخدامها كقيمة. انها مجرد رقم بعد كل شيء.

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

أنا استخدم Cafebabe لم أره يستخدمه أي موزعين من قبل.

int *i = 0xDEADBEEF;
// god knows if that location is available

int i = 0xDEADBEEF;
// what can go wrong?

إن الخطر الذي أراه هو نفسه في كلتا الحالتين: لقد قمت بإنشاء قيمة علامة لا تحتوي على سياق فوري. لا يوجد شيء عن i في كلتا الحالتين، سيعرفني 100 أو 1000 أو 10000 خطوط أن هناك قيمة علمية محتملة مرتبطة بها. ما تزرعه هو علة لغم أرضي، إذا كنت لا أتذكر التحقق من ذلك في كل استخدام ممكن، فيمكن أن أخفق مع مشكلة تصحيحات رهيبة. كل استخدام i سوف تضطر الآن إلى أن تبدو مثل هذا:

if (i != 0xDEADBEEF) { // Curse the original designer to oblivion
    // Actual useful work goes here
}

كرر ما سبق لجميع الحالات 7000 حيث تحتاج إلى استخدام i في التعليمات البرمجية الخاصة بك.

الآن، لماذا هو ما سبق أسوأ من هذا؟

if (isIProperlyInitialized()) { // Which could just be a boolean
    // Actual useful work goes here
}

بحد أدنى، يمكنني اكتشاف العديد من القضايا الحرجة:

  1. الإملائية: أنا مطبوع فظيع. ما مدى سهولة اكتشاف 0xdaedbeef في مراجعة التعليمات البرمجية؟ أو 0xDeadBEFF؟ من ناحية أخرى، أعلم أن تجويع بلدي سوف بارف على الفور على iSiproperlyinitialised () (أدخل الإلزامية س ضد. z. مناقشة هنا).
  2. التعرض للمعنى. وبعد بدلا من محاولة إخفاء أعلامك في التعليمات البرمجية، فقد قمت بإنشاء طريقة عمدا التي يمكن أن ترى بقية الرمز.
  3. فرص الاقتران. وبعد من الممكن تماما أن تكون مؤشر أو مرجع متصل بذاكرة التخزين المؤقت المحددة بشكل فضفاض. يمكن تحميل التحقق من التهيئة للتحقق في التحقق أولا إذا كانت القيمة في ذاكرة التخزين المؤقت، ثم محاولة إعادة تشغيلها مرة أخرى إلى ذاكرة التخزين المؤقت، وإذا فشل كل ما يفشل، فأرجأ خطأ.

باختصار، من السهل كتابة الرمز الذي تحتاجه حقا لأنه خلق قيمة سحرية غامضة. سيقوم برمز المشرف في المستقبل (الذي من المحتمل جدا أن تكون أنت) شكرا لك.

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