هل تريد تغيير __FILE__ و__LINE__ في التعليمات البرمجية للاقتباس؟

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

  •  02-07-2019
  •  | 
  •  

سؤال

هل هناك طريقة للحصول على المعالج المسبق لـ C/C++ أو قالب أو ما شابه ذلك لتشويه/تجزئة __FILE__ و__LINE__ وربما بعض المدخلات الخارجية الأخرى مثل رقم البنية في رقم قصير واحد يمكن اقتباسه في السجلات أو رسائل الخطأ؟

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

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

المحلول

سيتعين عليك استخدام وظيفة لإجراء التجزئة وإنشاء رمز منها __LINE__ و __FILE__ نظرًا لأن المعالج الأولي للغة C غير قادر على القيام بمثل هذه المهام المعقدة.

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

نصائح أخرى

حسنًا...يمكنك استخدام شيء مثل:

((*(int*)__FILE__ && 0xFFFF0000) | version << 8 | __LINE__ )

لن يكون الأمر فريدًا تمامًا، ولكنه قد يعمل لتحقيق ما تريد.يمكن تغيير هذه العمليات إلى +، والتي قد تعمل بشكل أفضل مع بعض الأشياء.

وبطبيعة الحال، إذا كان بإمكانك بالفعل إنشاء رمز تجزئة، فمن المحتمل أن ترغب في القيام بذلك.

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

(تم ذلك في D لذا قد لا يكون ممكنًا في C++)

template Serial(char[] file, int line)
{
    prgams(msg, 
    "template Serial(char[] file : \"~file~"\", int line : "~line.stringof~")"
      "{const int Serial = __LINE__;");
    const int Serial = -1;
}

سيكون الحل الأبسط هو الاحتفاظ بمتغير "موقع الخطأ" الثابت العالمي.

#ifdef DEBUG
#define trace_here(version) printf("[%d]%s:%d {%d}\n", version, __FILE__, __LINE__, errloc++);
#else
#define trace_here(version) printf("{%lu}\n", version<<16|errloc++);
#endif

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

ستحتاج إلى تضمين الإصدار أو رقم الإصدار، لأن مواقع الأخطاء هذه قد تتغير مع أي إصدار.

لا يعمل بشكل جيد إذا لم تتمكن من إعادة إنتاج مسارات التعليمات البرمجية.

__FILE__ هو مؤشر إلى قسم الثوابت في برنامجك.إذا قمت بإخراج الفرق بين ذلك وبين ثابت آخر، فيجب أن تحصل على نتيجة مستقلة عن أي عملية نقل، وما إلى ذلك:

extern const char g_DebugAnchor;
#define FILE_STR_OFFSET (__FILE__ - &g_DebugAnchor)

يمكنك بعد ذلك الإبلاغ عن ذلك، أو دمجه بطريقة ما مع رقم السطر، وما إلى ذلك.من المحتمل أن تكون الأجزاء الوسطى من FILE_STR_OFFSET هي الأكثر إثارة للاهتمام.

حسنًا، إذا كنت تعرض الرسالة للمستخدم بنفسك (بدلاً من عرض عنوان العطل أو الوظيفة بواسطة النظام)، فلا يوجد ما يمنعك من عرض ما تريده بالضبط.

على سبيل المثال:

typedef union ErrorCode {
    struct {
        unsigned int file: 15;
        unsigned int line: 12; /* Better than 5 bits, still not great
                                  Thanks commenters!! */
        unsigned int build: 5;
    } bits;
    unsigned int code;
} ErrorCode;

unsigned int buildErrorCodes(const char *file, int line, int build)
{
    ErrorCode code;
    code.bits.line=line   & ((1<<12) - 1);
    code.bits.build=build & ((1<< 5) - 1);
    code.bits.file=some_hash_function(file) & ((1<<15) - 1);

    return code.code;
}

ستستخدم ذلك كـ

buildErrorCodes(__FILE__, __LINE__, BUILD_CODE) 

وإخراجها في الست عشري.لن يكون من الصعب فك رموزها..

(تم التعديل - المعلقون على حق، لا بد أنني كنت مجنونًا لتحديد 5 بتات لرقم السطر.ومع ذلك، من غير المحتمل أن تتعارض الخطوط التي تحتوي على رسائل خطأ في Modulo 4096.5 بتات للإنشاء لا تزال جيدة - modulo 32 يعني أن 32 نسخة فقط يمكن أن تكون معلقة وأن الخطأ لا يزال يحدث في نفس السطر.)

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