সিতে ডিবাগ প্রিন্টিংয়ের জন্য # ডেফাইন ম্যাক্রো?


209

নিম্নলিখিত সিউডো কোডের মতো, DEBUG সংজ্ঞায়িত করা হলে এমন ম্যাক্রো তৈরি করার চেষ্টা করা হচ্ছে যা প্রিন্ট ডিবাগ বার্তাগুলির জন্য ব্যবহার করা যেতে পারে:

#define DEBUG 1
#define debug_print(args ...) if (DEBUG) fprintf(stderr, args)

এটি ম্যাক্রো দিয়ে কীভাবে সম্পন্ন হয়?


সংকলক (জিসিসি) যদি (ডিইবিইউজি) {...} আউট, যদি প্রোডাকশন কোডে ডিইবিইউজি ম্যাক্রো 0 তে সেট থাকে তবে কী বিবৃতিগুলি অনুকূল করবে? আমি বুঝতে পারি যে সংকলকটির কাছে ডিবাগের বিবৃতিগুলি দৃশ্যমান করার উপযুক্ত কারণ রয়েছে তবে একটি খারাপ অনুভূতি থেকে যায়। -প্যাট
প্যাট

উত্তর:


410

আপনি যদি C99 বা তার পরে সংকলক ব্যবহার করেন

#define debug_print(fmt, ...) \
            do { if (DEBUG) fprintf(stderr, fmt, __VA_ARGS__); } while (0)

এটি ধরে নিয়েছে যে আপনি সি 99 ব্যবহার করছেন (ভেরিয়েবল যুক্তি তালিকার তালিকাটি পূর্ববর্তী সংস্করণগুলিতে সমর্থিত নয়)। do { ... } while (0)বাগ্ধারা নিশ্চিত কোড একটি বিবৃতি (ফাংশন কল) -এর মত কাজ করে যে। কোডের নিঃশর্ত ব্যবহার নিশ্চিত করে যে কম্পাইলার সর্বদা আপনার ডিবাগ কোডটি বৈধ কিনা তা পরীক্ষা করে - তবে ডিইবিইউজি 0 হলে অপ্টিমাইজার কোডটি সরিয়ে ফেলবে।

আপনি যদি #ifdef DEBUG এর সাথে কাজ করতে চান তবে পরীক্ষার শর্তটি পরিবর্তন করুন:

#ifdef DEBUG
#define DEBUG_TEST 1
#else
#define DEBUG_TEST 0
#endif

এবং তারপরে DEBUG_TEST ব্যবহার করুন যেখানে আমি DEBUG ব্যবহার করেছি।

আপনি ফরম্যাট স্ট্রিং (সম্ভবত একটি ভাল ধারণা যাহাই হউক না কেন), তবে আপনাকে ভালো জিনিস পরিচয় করিয়ে দিতে পারেন জন্য একটি স্ট্রিং আক্ষরিক পীড়াপীড়ি যদি __FILE__, __LINE__এবং __func__আউটপুট, যা ডায়গনিস্টিক উন্নত করতে পারেন মধ্যে:

#define debug_print(fmt, ...) \
        do { if (DEBUG) fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, \
                                __LINE__, __func__, __VA_ARGS__); } while (0)

এটি প্রোগ্রামার লেখার চেয়ে বড় ফর্ম্যাট স্ট্রিং তৈরি করতে স্ট্রিং কনটেনটেশনের উপর নির্ভর করে।

আপনি যদি C89 সংকলক ব্যবহার করেন

আপনি যদি C89 এর সাথে আটকে থাকেন এবং কোনও কার্যকর সংকলক এক্সটেনশান নেই, তবে এটি হ্যান্ডেল করার কোনও বিশেষ উপায় নেই। আমি যে কৌশলটি ব্যবহার করতাম তা হ'ল:

#define TRACE(x) do { if (DEBUG) dbg_printf x; } while (0)

এবং তারপরে কোডটিতে লিখুন:

TRACE(("message %d\n", var));

দ্বৈত-বন্ধনীগুলি গুরুত্বপূর্ণ - এবং ম্যাক্রো প্রসারণে আপনার মজার স্বরলিপি রয়েছে have আগের মতো, সংকলক সর্বদা সিন্ট্যাকটিক বৈধতার কোডটি যাচাই করে (যা ভাল) তবে অপ্টিমাইজার কেবল তখনই মুদ্রণ ফাংশনটির জন্য অনুরোধ করে যদি ডিইবিইউজি ম্যাক্রো অ-শূন্যে মূল্যায়ন করে।

এটির জন্য একটি সমর্থন ফাংশন প্রয়োজন - উদাহরণস্বরূপ dbg_printf () - 'স্ট্যাডার' এর মতো জিনিসগুলি পরিচালনা করতে। ভ্যারাগস ফাংশনগুলি কীভাবে লিখবেন তা আপনার জানা দরকার, তবে এটি কঠিন নয়:

#include <stdarg.h>
#include <stdio.h>

void dbg_printf(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
}

আপনি অবশ্যই এই কৌশলটি সি 99 এ ব্যবহার করতে পারেন, তবে __VA_ARGS__কৌশলটি আরও সুন্দর কারণ এটি নিয়মিত ফাংশন স্বরলিপি ব্যবহার করে, ডাবল-বন্ধনী হ্যাক করে না।

সংকলক সর্বদা ডিবাগ কোডটি দেখেন কেন এটি গুরুত্বপূর্ণ?

[ অন্য উত্তরে মন্তব্য করা পুনরায় পোস্ট করা। ]

উপরোক্ত C99 এবং C89 উভয় বাস্তবায়নের পিছনে একটি কেন্দ্রীয় ধারণা হ'ল সংকলক যথাযথভাবে ডিবাগিং প্রিন্টফ-এর মতো বিবৃতি দেখে। এটি দীর্ঘমেয়াদী কোডের জন্য গুরুত্বপূর্ণ - কোড যা এক বা দুই দশক চলবে।

ধরুন একটি টুকরা কোড বেশিরভাগ বছর ধরে বেশিরভাগ সুপ্ত (স্থিতিশীল) ছিল তবে এখন এটি পরিবর্তন করা দরকার। আপনি ডিবাগিং ট্রেসটিকে পুনরায় সক্ষম করেছেন - তবে ডিবাগিং (ট্রেসিং) কোডটি ডিবাগ করতে পেরে হতাশাজনক কারণ এটি স্থিতিশীল রক্ষণাবেক্ষণের বছরগুলিতে নাম পরিবর্তন করা বা পুনরায় টাইপ করা পরিবর্তনশীলগুলিকে বোঝায়। যদি সংকলক (পোস্ট প্রসেসর পোস্টকারী) সর্বদা মুদ্রণ বিবৃতিটি দেখে, এটি নিশ্চিত করে যে কোনও পার্শ্ববর্তী পরিবর্তনগুলি ডায়াগনস্টিকগুলিকে অকার্যকর করেনি। সংকলক মুদ্রণ বিবৃতিটি না দেখলে, এটি আপনাকে আপনার নিজের অসতর্কতা (বা আপনার সহকর্মীদের বা সহযোগীদের অসতর্কতা) থেকে রক্ষা করতে পারে না। কার্নিগান এবং পাইকের ' প্রোগ্রামিং অনুশীলন ' দেখুন , বিশেষ করে অধ্যায় 8 ( টিপিওপিতে উইকিপিডিয়া দেখুন )।

এটি 'সেখানে রয়েছে, এটি হয়েছে' অভিজ্ঞতা - আমি মূলত অন্যান্য উত্তরে বর্ণিত কৌশলটি ব্যবহার করেছি যেখানে নন-ডিবাগ বিল্ডটি বেশ কয়েক বছর ধরে (এক দশকেরও বেশি সময়) মুদ্রণের মতো বিবৃতি দেখতে পায় না। তবে আমি টিপিওপিতে পরামর্শটি পেয়েছিলাম (আমার পূর্ববর্তী মন্তব্যটি দেখুন), এবং তারপরে বেশ কয়েকটি বছর পরে কিছু ডিবাগিং কোড সক্ষম করেছিলাম এবং ডিবাগটি ভেঙে পরিবর্তিত প্রসঙ্গে সমস্যার মধ্যে পড়েছিলাম। বেশিরভাগ সময়, মুদ্রণটিকে সর্বদা বৈধ করা আমাকে পরবর্তী সমস্যাগুলি থেকে বাঁচিয়েছে।

আমি কেবলমাত্র দৃser়তাগুলি নিয়ন্ত্রণ করতে NDEBUG এবং ডিবাগ ট্রেসিং প্রোগ্রামে অন্তর্নির্মিত কিনা তা নিয়ন্ত্রণ করতে একটি পৃথক ম্যাক্রো (সাধারণত ডিইবিইউজি) ব্যবহার করি। এমনকি যখন ডিবাগ ট্রেসিং অন্তর্নির্মিত হয়, আমি প্রায়শই চাই না যে ডিবাগ আউটপুটটি নিঃশর্তভাবে প্রদর্শিত হোক, তাই আউটপুট প্রদর্শিত হবে কিনা তা নিয়ন্ত্রণ করার আমার কাছে ব্যবস্থা আছে (ডিবাগ স্তরগুলি, এবং fprintf()সরাসরি কল করার পরিবর্তে , আমি একটি ডিবাগ প্রিন্ট ফাংশন কল করি যা কেবল শর্তসাপেক্ষে মুদ্রণ করে সুতরাং কোডের একই বিল্ডটি প্রোগ্রাম বিকল্পগুলির উপর ভিত্তি করে মুদ্রণ করতে বা মুদ্রণ করতে পারে)। বড় প্রোগ্রামগুলির জন্য আমার কোডটির একটি 'মাল্টিপল-সাবসিস্টেম' সংস্করণও রয়েছে, যাতে আমার কাছে প্রোগ্রামের বিভিন্ন বিভাগ বিভিন্ন পরিমাণে ট্রেস তৈরি করতে পারে - রানটাইম নিয়ন্ত্রণের অধীনে।

আমি পরামর্শ দিচ্ছি যে সমস্ত বিল্ডের জন্য, সংকলকটি ডায়াগনস্টিক স্টেটমেন্টগুলি দেখতে হবে; যাইহোক, সংকলক ডিবাগ সক্ষম করা না থাকলে ডিবাগিং ট্রেস স্টেটমেন্টগুলির জন্য কোনও কোড উত্পন্ন করবে না। মূলত, এর অর্থ হ'ল প্রতিটি বার সংকলক দ্বারা আপনার কোডগুলি যাচাই বা ডিবাগিংয়ের জন্য পরীক্ষা করা হয়। এটি একটি ভাল জিনিস!

debug.h - সংস্করণ 1.2 (1990-05-01)

/*
@(#)File:            $RCSfile: debug.h,v $
@(#)Version:         $Revision: 1.2 $
@(#)Last changed:    $Date: 1990/05/01 12:55:39 $
@(#)Purpose:         Definitions for the debugging system
@(#)Author:          J Leffler
*/

#ifndef DEBUG_H
#define DEBUG_H

/* -- Macro Definitions */

#ifdef DEBUG
#define TRACE(x)    db_print x
#else
#define TRACE(x)
#endif /* DEBUG */

/* -- Declarations */

#ifdef DEBUG
extern  int     debug;
#endif

#endif  /* DEBUG_H */

debug.h - সংস্করণ 3.6 (২০০৮-০২-১১)

/*
@(#)File:           $RCSfile: debug.h,v $
@(#)Version:        $Revision: 3.6 $
@(#)Last changed:   $Date: 2008/02/11 06:46:37 $
@(#)Purpose:        Definitions for the debugging system
@(#)Author:         J Leffler
@(#)Copyright:      (C) JLSS 1990-93,1997-99,2003,2005,2008
@(#)Product:        :PRODUCT:
*/

#ifndef DEBUG_H
#define DEBUG_H

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */

/*
** Usage:  TRACE((level, fmt, ...))
** "level" is the debugging level which must be operational for the output
** to appear. "fmt" is a printf format string. "..." is whatever extra
** arguments fmt requires (possibly nothing).
** The non-debug macro means that the code is validated but never called.
** -- See chapter 8 of 'The Practice of Programming', by Kernighan and Pike.
*/
#ifdef DEBUG
#define TRACE(x)    db_print x
#else
#define TRACE(x)    do { if (0) db_print x; } while (0)
#endif /* DEBUG */

#ifndef lint
#ifdef DEBUG
/* This string can't be made extern - multiple definition in general */
static const char jlss_id_debug_enabled[] = "@(#)*** DEBUG ***";
#endif /* DEBUG */
#ifdef MAIN_PROGRAM
const char jlss_id_debug_h[] = "@(#)$Id: debug.h,v 3.6 2008/02/11 06:46:37 jleffler Exp $";
#endif /* MAIN_PROGRAM */
#endif /* lint */

#include <stdio.h>

extern int      db_getdebug(void);
extern int      db_newindent(void);
extern int      db_oldindent(void);
extern int      db_setdebug(int level);
extern int      db_setindent(int i);
extern void     db_print(int level, const char *fmt,...);
extern void     db_setfilename(const char *fn);
extern void     db_setfileptr(FILE *fp);
extern FILE    *db_getfileptr(void);

/* Semi-private function */
extern const char *db_indent(void);

/**************************************\
** MULTIPLE DEBUGGING SUBSYSTEMS CODE **
\**************************************/

/*
** Usage:  MDTRACE((subsys, level, fmt, ...))
** "subsys" is the debugging system to which this statement belongs.
** The significance of the subsystems is determined by the programmer,
** except that the functions such as db_print refer to subsystem 0.
** "level" is the debugging level which must be operational for the
** output to appear. "fmt" is a printf format string. "..." is
** whatever extra arguments fmt requires (possibly nothing).
** The non-debug macro means that the code is validated but never called.
*/
#ifdef DEBUG
#define MDTRACE(x)  db_mdprint x
#else
#define MDTRACE(x)  do { if (0) db_mdprint x; } while (0)
#endif /* DEBUG */

extern int      db_mdgetdebug(int subsys);
extern int      db_mdparsearg(char *arg);
extern int      db_mdsetdebug(int subsys, int level);
extern void     db_mdprint(int subsys, int level, const char *fmt,...);
extern void     db_mdsubsysnames(char const * const *names);

#endif /* DEBUG_H */

সি 99 বা তার পরে একক আর্গুমেন্ট বৈকল্পিক

কাইল ব্র্যান্ড জিজ্ঞাসা করেছে:

যাইহোক এটি করার debug_printজন্য কোনও যুক্তি না থাকলেও এখনও কাজ করে? উদাহরণ স্বরূপ:

    debug_print("Foo");

একটি সাধারণ, পুরানো কালের হ্যাক রয়েছে:

debug_print("%s\n", "Foo");

নীচে প্রদর্শিত জিসিসির একমাত্র সমাধানও এর জন্য সমর্থন সরবরাহ করে।

তবে আপনি এটি ব্যবহার করে সরাসরি সি 99 সিস্টেমের মাধ্যমে এটি করতে পারেন:

#define debug_print(...) \
            do { if (DEBUG) fprintf(stderr, __VA_ARGS__); } while (0)

প্রথম সংস্করণের তুলনায়, আপনি সীমিত চেকিংটি হারাতে পারেন যার জন্য 'fmt' আর্গুমেন্টের প্রয়োজন, যার অর্থ হল যে কেউ 'ডিবাগ_প্রিন্ট ()' কল করতে চেষ্টা করতে পারে কোনও যুক্তি ছাড়াই (তবে আর্গুমেন্ট তালিকার পিছনে থাকা কমাটি fprintf()সংকলন করতে ব্যর্থ হবে) । যাচাইয়ের ক্ষতি একেবারেই সমস্যা কিনা তা বিতর্কযোগ্য।

একক যুক্তির জন্য জিসিসি-নির্দিষ্ট কৌশল

কিছু সংকলক ম্যাক্রোগুলিতে পরিবর্তনশীল-দৈর্ঘ্যের আর্গুমেন্ট তালিকাগুলি হ্যান্ডল করার অন্যান্য উপায়ে এক্সটেনশনের প্রস্তাব দিতে পারে। বিশেষত, হুগো ইডেলারের মন্তব্যগুলিতে প্রথম হিসাবে উল্লেখ করা হয়েছে , জিসিসি আপনাকে ম্যাক্রোর সর্বশেষ 'স্থির' যুক্তির পরে সাধারণত যে কমাটি উপস্থিত হবে তা বাদ দিতে দেয়। এটি আপনাকে ##__VA_ARGS__ম্যাক্রো প্রতিস্থাপন পাঠ্যেও ব্যবহার করতে দেয় , যা স্বরলিখনের পূর্ববর্তী কমাটি মুছে ফেলে তবে কেবল যদি পূর্ববর্তী টোকনটি কমা হয়:

#define debug_print(fmt, ...) \
            do { if (DEBUG) fprintf(stderr, fmt, ##__VA_ARGS__); } while (0)

বিন্যাসের পরে alচ্ছিক আর্গুমেন্ট গ্রহণ করার সময় এই সমাধানটি ফর্ম্যাট আর্গুমেন্টের প্রয়োজনীয়তার সুবিধা ধরে রাখে।

এই কৌশলটি এছাড়াও দ্বারা সমর্থিত ঝনঝন জিসিসি সামঞ্জস্যের জন্য।


কেন ডু-লুপ?

এখানকার উদ্দেশ্য কী do while?

আপনি ম্যাক্রোটি ব্যবহার করতে সক্ষম হতে চান তাই এটি কোনও ফাংশন কলের মতো দেখাচ্ছে, যার অর্থ এটি একটি অর্ধ-কোলন অনুসরণ করবে। অতএব, আপনি মামলা করতে ম্যাক্রো বডি প্যাকেজ করতে হবে। আপনি যদি ifআশেপাশের জায়গা ছাড়াই কোনও বিবৃতি ব্যবহার করেন তবে আপনার কাছে do { ... } while (0)থাকবে:

/* BAD - BAD - BAD */
#define debug_print(...) \
            if (DEBUG) fprintf(stderr, __VA_ARGS__)

এখন, ধরুন আপনি লিখেছেন:

if (x > y)
    debug_print("x (%d) > y (%d)\n", x, y);
else
    do_something_useful(x, y);

দুর্ভাগ্যক্রমে, সেই ইন্ডেন্টেশনটি প্রবাহের প্রকৃত নিয়ন্ত্রণকে প্রতিফলিত করে না, কারণ প্রিপ্রসেসর এটির সমান কোড তৈরি করে (প্রকৃত অর্থের উপর জোর দেওয়ার জন্য অভিযুক্ত এবং ধনুর্বন্ধনী):

if (x > y)
{
    if (DEBUG)
        fprintf(stderr, "x (%d) > y (%d)\n", x, y);
    else
        do_something_useful(x, y);
}

ম্যাক্রোতে পরবর্তী প্রচেষ্টা হতে পারে:

/* BAD - BAD - BAD */
#define debug_print(...) \
            if (DEBUG) { fprintf(stderr, __VA_ARGS__); }

এবং একই কোড খণ্ড এখন উত্পাদন করে:

if (x > y)
    if (DEBUG)
    {
        fprintf(stderr, "x (%d) > y (%d)\n", x, y);
    }
; // Null statement from semi-colon after macro
else
    do_something_useful(x, y);

এবং এটি elseএখন একটি সিনট্যাক্স ত্রুটি। do { ... } while(0)লুপ এড়াতে উভয় এই সমস্যা।

ম্যাক্রো লেখার অন্য একটি উপায় রয়েছে যা কাজ করতে পারে:

/* BAD - BAD - BAD */
#define debug_print(...) \
            ((void)((DEBUG) ? fprintf(stderr, __VA_ARGS__) : 0))

এটি প্রোগ্রামের খণ্ডটিকে বৈধ হিসাবে দেখায়। (void)ঢালাই প্রতিরোধ এটা প্রেক্ষিতে যেখানে একটি মান প্রয়োজন বোধ করা হয় ব্যবহৃত হচ্ছে - কিন্তু এটি একটি কমা অপারেটর যেখানে বাম প্রতীক হিসাবে ব্যবহার করা যেতে পারে do { ... } while (0)সংস্করণ করতে পারেন না। আপনি যদি ভাবেন যে এই জাতীয় অভিব্যক্তিগুলির মধ্যে আপনার ডিবাগ কোড এম্বেড করতে সক্ষম হওয়া উচিত তবে আপনি এটি পছন্দ করতে পারেন। আপনি যদি পূর্ণ বিবৃতি হিসাবে কাজ করতে ডিবাগ প্রিন্টের প্রয়োজন পছন্দ করেন তবে do { ... } while (0)সংস্করণটি আরও ভাল। মনে রাখবেন যে যদি ম্যাক্রোর শরীরে কোনও আধা-কলোন জড়িত (মোটামুটিভাবে বলা হয়), তবে আপনি কেবল do { ... } while(0)স্বরলিপিটি ব্যবহার করতে পারেন । এটি সর্বদা কাজ করে; এক্সপ্রেশন বিবৃতি প্রক্রিয়া প্রয়োগ করা আরও কঠিন হতে পারে। আপনি যে সংজ্ঞাটি এড়াতে পছন্দ করবেন তার সংকলক থেকে সতর্কতাও পেতে পারেন; এটি আপনার ব্যবহৃত সংকলক এবং পতাকাগুলির উপর নির্ভর করবে।


টিপিওপি আগে http://plan9.bell-labs.com/cm/cs/tpop এবং http://cm.bell-labs.com/cm/cs/tpop এ ছিল তবে উভয়ে এখন (2015-08-10) ভাঙ্গা।


গিটহাবে কোড

যদি তুমি জানতে আগ্রহী, আপনি GitHub এই কোড আমার এ সন্ধান করতে পারেন SOQ (স্ট্যাক ওভারফ্লো প্রশ্নাবলি) ফাইল হিসেবে সংগ্রহস্থলের debug.c, debug.hএবং mddebug.cমধ্যে src / libsoq উপ-নির্দেশিকা।


1
আমি মনে করি জিসিসি ## - gcc.gnu.org/onlinesocs/cpp/Variadic- ম্যাক্রোস এইচটিএমএল থেকে "একক যুক্তি সি 99 ভেরিয়েন্ট" শিরোনামের অধীনে উল্লেখ করা সার্থক হবে।
হুগো ইডেলার

2
বছর পরে, এবং এই উত্তরটি এখনও সমস্ত ইন্টারনেটগুলির মধ্যে সবচেয়ে দরকারী, কীভাবে ওরফে প্রিন্টক করা যায়! স্টিডিও উপলব্ধ না থাকায় কার্নেল স্পেসে vfprintf কাজ করে না। ধন্যবাদ! #define debug(...) \ do { if (DEBUG) \ printk("DRIVER_NAME:"); \ printk(__VA_ARGS__); \ printk("\n"); \ } while (0)
কেভিনফ

6
কীওয়ার্ডগুলির সাথে আপনার উদাহরণে __FILE__, __LINE__, __func__, __VA_ARGS__, আপনার কোনও প্রিন্টফ প্যারামিটার না থাকলে এটি সংকলন করবে না, অর্থাত্ যদি আপনি কেবল কল করেন debug_print("Some msg\n"); আপনি fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__); ## __ VA_ARGS__ ব্যবহার করে কোনও ফাংশন ছাড়িয়ে কোনও পরামিতি ছাড়তে পারবেন না।
এমসি_এলেক্ট্রন

1
@LogicTom: পার্থক্য মধ্যে #define debug_print(fmt, ...)এবং #define debug_print(...)। এর মধ্যে প্রথমটির জন্য কমপক্ষে একটি যুক্তি প্রয়োজন, ফর্ম্যাট স্ট্রিং ( fmt) এবং শূন্য বা আরও অনেক যুক্তি; দ্বিতীয়টির জন্য মোট শূন্য বা আরও বেশি আর্গুমেন্ট প্রয়োজন। আপনি যদি debug_print()প্রথমটির সাথে ব্যবহার করেন তবে আপনি ম্যাক্রোর অপব্যবহার সম্পর্কে প্রিপ্রোসেসর থেকে ত্রুটি পেয়েছেন, তবে দ্বিতীয়টি তা করে না। যাইহোক, আপনি এখনও সংকলন ত্রুটিগুলি পান কারণ প্রতিস্থাপন পাঠ্যটি বৈধ সি নয়, সুতরাং এটি সত্যিকার অর্থে খুব বেশি পার্থক্য নয় - সুতরাং 'সীমিত পরীক্ষা' শব্দের ব্যবহার।
জোনাথন লেফলার

1
@ সেন্টার্টারিওর উপরে পরিবর্তিত দেখানো রূপটি পুরো অ্যাপ্লিকেশন জুড়ে একটি একক সক্রিয় ডিবাগিং স্তর ব্যবহার করে এবং প্রোগ্রামটি চলাকালীন আমি সাধারণত ডিবাগিং স্তরটি সেট করার জন্য কমান্ড লাইন বিকল্পগুলি ব্যবহার করি। আমারও একটি বৈকল্পিক রয়েছে যা একাধিক পৃথক সাবসিস্টেমগুলি স্বীকৃতি দেয়, যার প্রত্যেকটির একটি নাম এবং নিজস্ব ডিবাগিং স্তর দেওয়া হয়, যাতে আমি -D input=4,macros=9,rules=2ইনপুট সিস্টেমের ডিবাগ স্তরটি 4, ম্যাক্রো সিস্টেম 9 তে সেট করতে (তীব্র তদন্তের মধ্য দিয়ে যাচ্ছি) ) এবং বিধি ব্যবস্থা 2 এ থিমটিতে অন্তহীন বিভিন্নতা রয়েছে; আপনার উপযুক্ত অনুসারে যা ব্যবহার করুন।
জোনাথন লেফলার

28

আমি এই জাতীয় কিছু ব্যবহার:

#ifdef DEBUG
 #define D if(1) 
#else
 #define D if(0) 
#endif

আমি কেবলমাত্র একটি উপসর্গ হিসাবে ডি ব্যবহার করি:

D printf("x=%0.3f\n",x);

সংকলকটি ডিবাগ কোডটি দেখে, কোনও কমা সমস্যা নেই এবং এটি সর্বত্র কাজ করে। এছাড়াও যখন printfএটি পর্যাপ্ত না হয় তখন কাজ করে , যখন আপনাকে কোনও অ্যারে ফেলে দিতে হবে বা প্রোগ্রামের জন্য অপ্রয়োজনীয় এমন কিছু নির্ণয়ের মান গণনা করুন তখন বলুন।

সম্পাদনা: ঠিক আছে, এটি কোনও সমস্যা তৈরি করতে পারে যখন elseকাছাকাছি কোথাও এই ইনজেকশনটি দিয়ে বাধা দেওয়া যেতে পারে if। এটি একটি সংস্করণ যা এটির ওপরে চলেছে:

#ifdef DEBUG
 #define D 
#else
 #define D for(;0;)
#endif

3
যেমন for(;0;)আপনি যখন D continue;বা এর মতো কিছু লেখেন তখন এটি সমস্যা তৈরি করতে পারে D break;
এসিক্রিটার

1
আমাকে পেয়েছে; যদিও এটি দুর্ঘটনায় ঘটতে পারে তা খুব অসম্ভব বলে মনে হয়।
এমবিকিউ

11

পোর্টেবল (আইএসও সি 90) বাস্তবায়নের জন্য আপনি ডাবল প্রথম বন্ধনী ব্যবহার করতে পারেন, এটির মতো;

#include <stdio.h>
#include <stdarg.h>

#ifndef NDEBUG
#  define debug_print(msg) stderr_printf msg
#else
#  define debug_print(msg) (void)0
#endif

void
stderr_printf(const char *fmt, ...)
{
  va_list ap;
  va_start(ap, fmt);
  vfprintf(stderr, fmt, ap);
  va_end(ap);
}

int
main(int argc, char *argv[])
{
  debug_print(("argv[0] is %s, argc is %d\n", argv[0], argc));
  return 0;
}

বা (হ্যাকিশ, এটি সুপারিশ করবে না)

#include <stdio.h>

#define _ ,
#ifndef NDEBUG
#  define debug_print(msg) fprintf(stderr, msg)
#else
#  define debug_print(msg) (void)0
#endif

int
main(int argc, char *argv[])
{
  debug_print("argv[0] is %s, argc is %d"_ argv[0] _ argc);
  return 0;
}

3
@ এলবি: প্রিপ্রোসেসরকে 'চিন্তা' করার জন্য কেবলমাত্র একটি যুক্তি রয়েছে, যখন _কে পরবর্তী পর্যায়ে প্রসারিত করতে দেওয়া হয়।
মার্সিন কোজুক

10

আমি যে সংস্করণটি ব্যবহার করি তা এখানে:

#ifdef NDEBUG
#define Dprintf(FORMAT, ...) ((void)0)
#define Dputs(MSG) ((void)0)
#else
#define Dprintf(FORMAT, ...) \
    fprintf(stderr, "%s() in %s, line %i: " FORMAT "\n", \
        __func__, __FILE__, __LINE__, __VA_ARGS__)
#define Dputs(MSG) Dprintf("%s", MSG)
#endif

9

আমি কিছু করতে হবে

#ifdef DEBUG
#define debug_print(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
#else
#define debug_print(fmt, ...) do {} while (0)
#endif

আমি মনে করি এটি পরিষ্কার।


আমি পতাকা হিসাবে পরীক্ষার অভ্যন্তরে ম্যাক্রো ব্যবহার করার ধারণাটি পছন্দ করি না। আপনি কি ব্যাখ্যা করতে পারবেন যে কেন সবসময় ডিবাগ প্রিন্টিং চেক করা উচিত?
এলবি 40

1
@ জোনাথন: কোডটি যদি কেবল কখনও ডিবাগ মোডে কার্যকর হয় তবে এটি কেন ডিবাগ মোডে সংকলন করে আপনার যত্ন নেওয়া উচিত? assert()stdlib থেকে একইভাবে কাজ করে এবং আমি সাধারণত NDEBUGআমার নিজের ডিবাগিং কোডের জন্য ম্যাক্রোটি পুনরায় ব্যবহার করি ...
ক্রিস্টোফ

পরীক্ষায় DEBUG ব্যবহার করে, কেউ যদি অনিয়ন্ত্রিত অপরিশোধিত DEBUG করেন, আপনার কোড আর সংকলন করে না। ঠিক?
LB40

4
এটি ডিবাগিং সক্ষম করতে হতাশ এবং তারপরে ডিবাগিং কোডটি ডিবাগ করতে হবে কারণ এটি পরিবর্তনশীলগুলির নাম উল্লেখ করে যা পুনরায় নামকরণ করা হয়েছে বা পুনরায় টাইপ করা হয়েছে ইত্যাদি। যদি সংকলক (পোস্ট প্রসেসর) সর্বদা মুদ্রণ বিবৃতিটি দেখে থাকে তবে এটি নিশ্চিত করে যে কোনও পার্শ্ববর্তী পরিবর্তন রয়েছে ডায়গনিস্টিকগুলি অকার্যকর নয়। সংকলক মুদ্রণ বিবৃতিটি না দেখলে, এটি আপনাকে আপনার নিজের অসতর্কতা (বা আপনার সহকর্মীদের বা সহযোগীদের অসতর্কতা) থেকে রক্ষা করতে পারে না। কার্নিঘান এবং পাইকের 'প্রোগ্রামিংয়ের অনুশীলন' দেখুন - plan9.bell-labs.com/cm/cs/tpop
জোনাথন লেফলার

1
@ ক্রিসটফ: ভাল, ধরণের ... আমি কেবলমাত্র দাবিগুলি নিয়ন্ত্রণ করতে NDEBUG এবং ডিবাগ ট্রেসিং নিয়ন্ত্রণ করতে একটি পৃথক ম্যাক্রো (সাধারণত ডিইবিইউজি) ব্যবহার করি। আমি প্রায়শই চাই না যে ডিবাগ আউটপুটটি নিঃশর্তভাবে প্রদর্শিত হোক, তাই আউটপুট প্রদর্শিত হবে কিনা তা নিয়ন্ত্রণ করার আমার কাছে ব্যবস্থা আছে (ডিবাগ স্তরগুলি, এবং সরাসরি এফপ্রিন্টফ () কল করার পরিবর্তে, আমি একটি ডিবাগ প্রিন্ট ফাংশন কল করি যা কেবল শর্তসাপেক্ষে প্রিন্ট করে তাই একই বিল্ডটি প্রিন্ট করে কোড প্রোগ্রাম অপশনগুলির উপর ভিত্তি করে মুদ্রণ করতে বা মুদ্রণ করতে পারে)। আমি পরামর্শ দিচ্ছি যে সমস্ত বিল্ডের জন্য, সংকলকটি ডায়াগনস্টিক স্টেটমেন্টগুলি দেখতে হবে; তবে, ডিবাগ সক্ষম না করা থাকলে এটি কোড উত্পন্ন করবে না।
জোনাথন লেফলার

8

Http://gcc.gnu.org/onlinesocs/cpp/Variadic- ম্যাক্রোস html এর মতে , ##আগে একটি হওয়া উচিত __VA_ARGS__

তা না হলে, একটি ম্যাক্রো #define dbg_print(format, ...) printf(format, __VA_ARGS__)নিম্নলিখিত উদাহরণে কম্পাইল না: dbg_print("hello world");


1
স্ট্যাক ওভারফ্লোতে আপনাকে স্বাগতম। আপনি ঠিক বলেছেন যে জিসিসির অ-মানক এক্সটেনশানটি আপনি উল্লেখ করেছেন। বর্তমানে গৃহীত উত্তরগুলিতে প্রকৃতপক্ষে এটি আপনার দেওয়া রেফারেন্স URL সহ উল্লেখ করে।
জোনাথন লেফলার

7
#define debug_print(FMT, ARGS...) do { \
    if (DEBUG) \
        fprintf(stderr, "%s:%d " FMT "\n", __FUNCTION__, __LINE__, ## ARGS); \
    } while (0)

সি এর কোন সংস্করণ সেই স্বরলিপি সমর্থন করে? এবং, যদি এটি কাজ করে, টোকেনটির মতো সমস্ত আর্গুমেন্ট আটকানো মানে এই যে আপনার কাছে বিন্যাসের স্ট্রিংয়ের জন্য খুব সীমিত বিকল্প রয়েছে, তাই না?
জোনাথন লেফলার

@ জোনাথন: জিসিসি (দেবিয়ান ৪.৩.৩-১৩) ৪.৩.৩
আইলাম

1
ঠিক আছে - একমত হয়েছে: এটি একটি পুরানো জিএনইউ এক্সটেনশন (জিসিসি ৪.৪.১ ম্যানুয়ালটির 5.17 ধারা) হিসাবে নথিভুক্ত করা হয়েছে। তবে আপনার সম্ভবত ডকুমেন্ট করা উচিত যে এটি কেবল জিসিসির সাথেই কাজ করবে - অথবা সম্ভবত আমরা আমাদের মধ্যে এই মন্তব্যগুলিতে করেছি।
জোনাথন লেফলার

1
আমার উদ্দেশ্যটি ছিল
আরোগুলি

2

এটি আমি ব্যবহার করি:

#if DBG
#include <stdio.h>
#define DBGPRINT printf
#else
#define DBGPRINT(...) /**/  
#endif

অতিরিক্ত যুক্তি ছাড়াই এমনকি প্রিন্টফকে সঠিকভাবে পরিচালনা করার চমৎকার সুবিধা রয়েছে। DBG == 0 এর ক্ষেত্রে, এমনকি নির্বোধ সংকলক চিবানোর কিছুই পায় না, সুতরাং কোনও কোড উত্পন্ন হয় না।


সংকলকটি সর্বদা ডিবাগ কোড চেক করা ভাল।
জোনাথন লেফলার

1

নীচের আমার প্রিয়টি হ'ল var_dump, যাকে বলা হয়:

var_dump("%d", count);

যেমন আউটপুট উত্পাদন করে:

patch.c:150:main(): count = 0

@ "জোনাথন লেফলার" এর কৃতিত্ব। সবাই সি 98-খুশি:

কোড

#define DEBUG 1
#include <stdarg.h>
#include <stdio.h>
void debug_vprintf(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
}

/* Call as: (DOUBLE PARENTHESES ARE MANDATORY) */
/* var_debug(("outfd = %d, somefailed = %d\n", outfd, somefailed)); */
#define var_debug(x) do { if (DEBUG) { debug_vprintf ("%s:%d:%s(): ", \
    __FILE__,  __LINE__, __func__); debug_vprintf x; }} while (0)

/* var_dump("%s" variable_name); */
#define var_dump(fmt, var) do { if (DEBUG) { debug_vprintf ("%s:%d:%s(): ", \
    __FILE__,  __LINE__, __func__); debug_vprintf ("%s = " fmt, #var, var); }} while (0)

#define DEBUG_HERE do { if (DEBUG) { debug_vprintf ("%s:%d:%s(): HERE\n", \
    __FILE__,  __LINE__, __func__); }} while (0)

1

সুতরাং, জিসিসি ব্যবহার করার সময়, আমি পছন্দ করি:

#define DBGI(expr) ({int g2rE3=expr; fprintf(stderr, "%s:%d:%s(): ""%s->%i\n", __FILE__,  __LINE__, __func__, #expr, g2rE3); g2rE3;})

কারণ এটি কোড সন্নিবেশ করা যেতে পারে।

মনে করুন আপনি ডিবাগ করার চেষ্টা করছেন

printf("%i\n", (1*2*3*4*5*6));

720

তারপরে আপনি এটিকে পরিবর্তন করতে পারেন:

printf("%i\n", DBGI(1*2*3*4*5*6));

hello.c:86:main(): 1*2*3*4*5*6->720
720

এবং কোনটি থেকে কী এক্সপ্রেশনকে মূল্যায়ন করা হয়েছিল তা বিশ্লেষণ পেতে পারেন।

এটি দ্বিগুণ মূল্যায়ন সমস্যার বিরুদ্ধে সুরক্ষিত, তবে সংক্ষিপ্ত শব্দগুলির অভাবে এটি নাম-সংঘর্ষের জন্য উন্মুক্ত রাখে।

তবে এটি বাসা করে:

DBGI(printf("%i\n", DBGI(1*2*3*4*5*6)));

hello.c:86:main(): 1*2*3*4*5*6->720
720
hello.c:86:main(): printf("%i\n", DBGI(1*2*3*4*5*6))->4

সুতরাং আমি মনে করি যে যতক্ষণ আপনি g2rE3 পরিবর্তনশীল নাম হিসাবে ব্যবহার করা এড়াবেন না ততক্ষণ আপনি ঠিক থাকবেন।

অবশ্যই আমি এটি খুঁজে পেয়েছি (এবং স্ট্রিংয়ের সাথে যুক্ত সংস্করণ এবং ডিবাগ স্তরের সংস্করণ ইত্যাদি) অমূল্য।


1

আমি বছরের পর বছর ধরে কীভাবে এটি করব সে সম্পর্কে স্টিও করছি এবং শেষ পর্যন্ত একটি সমাধান নিয়ে এসেছি। তবে, আমি জানতাম না যে এখানে ইতিমধ্যে অন্যান্য সমাধানগুলি রয়েছে। প্রথমত, লেফ্লারের উত্তরের সাথে পার্থক্য নিয়ে , আমি তার যুক্তিটি দেখছি না যে ডিবাগ প্রিন্টগুলি সর্বদা সংকলিত করা উচিত। আমি বরং আমার প্রকল্পে প্রচুর অনাঙ্কিত কোড কার্যকর করতে চাই না, যখন প্রয়োজন হয় না, এমন ক্ষেত্রে যেখানে আমার পরীক্ষা করার প্রয়োজন হয় এবং তারা অপ্টিমাইজড নাও হতে পারে।

প্রতিবার সংকলন না করা প্রকৃত অনুশীলনের চেয়ে খারাপ শোনাতে পারে। আপনি কখনও কখনও সংকলন না এমন ডিবাগ প্রিন্টগুলি দিয়ে শেষ করেন তবে কোনও প্রকল্প চূড়ান্ত করার আগে সেগুলি সংকলন এবং পরীক্ষা করা এত কঠিন নয়। এই সিস্টেমের সাহায্যে, আপনি যদি তিন স্তরের ডিবাগ ব্যবহার করছেন, কেবল এটি ডিবাগ বার্তা স্তর তিনটিতে রাখুন, আপনার সংকলন ত্রুটিগুলি ঠিক করুন এবং আপনি ইয়ার কোডটি চূড়ান্ত করার আগে অন্য কোনওটির জন্য পরীক্ষা করুন। (অবশ্যই, ডিবাগ স্টেটমেন্টগুলি সংকলন করা কোনও গ্যারান্টি নয় যে তারা এখনও উদ্দিষ্ট হিসাবে কাজ করছে))

আমার সমাধানটি ডিবাগ বিশদের স্তরেরও সরবরাহ করে; এবং আপনি যদি এটি সর্বোচ্চ স্তরে সেট করেন তবে সেগুলি সমস্ত সংকলন করে। আপনি যদি সম্প্রতি একটি উচ্চ ডিবাগ বিশদ স্তরের ব্যবহার করে থাকেন তবে তারা সকলেই সেই সময়ে সংকলন করতে সক্ষম হয়েছিল। চূড়ান্ত আপডেটগুলি বেশ সহজ হওয়া উচিত। আমার কখনও তিনটি স্তরের বেশি প্রয়োজন হয় নি, তবে জোনাথন বলেছেন তিনি নয়টি ব্যবহার করেছেন। এই পদ্ধতিটি (লেফ্লারের মতো) যে কোনও স্তরে বাড়ানো যেতে পারে। আমার পদ্ধতির ব্যবহার সহজ হতে পারে; আপনার কোড ব্যবহার করার সময় মাত্র দুটি বিবৃতি প্রয়োজন। আমি অবশ্য ক্লোজ ম্যাক্রোকেও কোডিং করছি - যদিও এটি কিছুই করে না। আমি যদি কোনও ফাইলে প্রেরণ করছিলাম তবে এটি হতে পারে।

খরচের বিপরীতে তাদের পরীক্ষা করার অতিরিক্ত ধাপটি দেখুন যে তারা প্রসবের আগে সংকলন করবে, তা হ'ল

  1. আপনাকে অনুকূলিতকরণের জন্য তাদের অবশ্যই আস্থা রাখতে হবে, যদি আপনার পর্যাপ্ত অপ্টিমাইজেশন স্তর থাকে তবে অবশ্যই তা ঘটতে হবে।
  2. তদ্ব্যতীত, তারা পরীক্ষার উদ্দেশ্যে (যা স্বীকার করা বিরল) এর জন্য বন্ধ করে দেওয়া অপটিমাইজেশন সহ কোনও রিলিজ সংকলন করলে তারা সম্ভবত না করবে; এবং তারা অবশ্যই ডিবাগের সময় মোটেও তা করবে না - যার ফলে রানটাইমের সময় কয়েক ডজন বা শত শত "যদি (ডিইবিইউজি)" বিবৃতি কার্যকর করা হয়; এইভাবে মৃত্যুদণ্ড কার্যকর করা (যা আমার নীতিগত আপত্তি) এবং কম গুরুত্বপূর্ণ, আপনার নির্বাহযোগ্য বা dll আকার বাড়িয়ে তোলা; এবং তাই নির্বাহ এবং সময় সংকলন। জোনাথন, তবে আমাকে জানান, তাঁর পদ্ধতিটিও বিবৃতি সংকলন না করে তৈরি করা যেতে পারে।

আধুনিক প্রাক-আনয়ন প্রসেসরগুলিতে শাখাগুলি আসলে তুলনামূলকভাবে বেশ ব্যয়বহুল। আপনার অ্যাপ্লিকেশন সময়-সমালোচনামূলক না হলে সম্ভবত কোনও বড় বিষয় নয়; তবে যদি পারফরম্যান্সটি কোনও সমস্যা হয় তবে হ্যাঁ, একটি বৃহত যথেষ্ট চুক্তি যা আমি কিছুটা দ্রুত-সম্পাদনকারী ডিবাগ কোডের জন্য বেছে নিতে পছন্দ করি (এবং সম্ভবত দ্রুত রিলিজ, বিরল ক্ষেত্রে, যেমন উল্লেখ করা হয়েছে)।

সুতরাং, আমি যা চাইছিলাম তা একটি ডিবাগ প্রিন্ট ম্যাক্রো যা এটি মুদ্রণযোগ্য নয় তা সংকলন করে না, তবে তা করে। আমি ডিবাগিংয়ের স্তরগুলিও চেয়েছিলাম, যাতে, উদাহরণস্বরূপ যদি আমি কোডটির পারফরম্যান্সের-গুরুত্বপূর্ণ অংশগুলি চাইতাম যে কোনও সময়ে মুদ্রণ না করা, তবে অন্যকে মুদ্রণ করতে, আমি একটি ডিবাগ স্তর নির্ধারণ করতে পারি, এবং অতিরিক্ত ডিবাগ প্রিন্ট কিক ইন করতে পারি I ডিবাগ স্তরগুলি প্রয়োগ করতে এমন একটি উপায় জুড়ে এসেছিল যা নির্ধারণ করে যে মুদ্রণটি এমনকি সংকলিত হয়েছে কিনা। আমি এটি এইভাবে অর্জন করেছি:

DebugLog.h:

// FILE: DebugLog.h
// REMARKS: This is a generic pair of files useful for debugging.  It provides three levels of 
// debug logging, currently; in addition to disabling it.  Level 3 is the most information.
// Levels 2 and 1 have progressively more.  Thus, you can write: 
//     DEBUGLOG_LOG(1, "a number=%d", 7);
// and it will be seen if DEBUG is anything other than undefined or zero.  If you write
//     DEBUGLOG_LOG(3, "another number=%d", 15);
// it will only be seen if DEBUG is 3.  When not being displayed, these routines compile
// to NOTHING.  I reject the argument that debug code needs to always be compiled so as to 
// keep it current.  I would rather have a leaner and faster app, and just not be lazy, and 
// maintain debugs as needed.  I don't know if this works with the C preprocessor or not, 
// but the rest of the code is fully C compliant also if it is.

#define DEBUG 1

#ifdef DEBUG
#define DEBUGLOG_INIT(filename) debuglog_init(filename)
#else
#define debuglog_init(...)
#endif

#ifdef DEBUG
#define DEBUGLOG_CLOSE debuglog_close
#else
#define debuglog_close(...)
#endif

#define DEBUGLOG_LOG(level, fmt, ...) DEBUGLOG_LOG ## level (fmt, ##__VA_ARGS__)

#if DEBUG == 0
#define DEBUGLOG_LOG0(...)
#endif

#if DEBUG >= 1
#define DEBUGLOG_LOG1(fmt, ...) debuglog_log (fmt, ##__VA_ARGS__)
#else
#define DEBUGLOG_LOG1(...)
#endif

#if DEBUG >= 2
#define DEBUGLOG_LOG2(fmt, ...) debuglog_log (fmt, ##__VA_ARGS__)
#else
#define DEBUGLOG_LOG2(...)
#endif

#if DEBUG == 3
#define DEBUGLOG_LOG3(fmt, ...) debuglog_log (fmt, ##__VA_ARGS__)
#else
#define DEBUGLOG_LOG3(...)
#endif

void debuglog_init(char *filename);
void debuglog_close(void);
void debuglog_log(char* format, ...);

DebugLog.cpp:

// FILE: DebugLog.h
// REMARKS: This is a generic pair of files useful for debugging.  It provides three levels of 
// debug logging, currently; in addition to disabling it.  See DebugLog.h's remarks for more 
// info.

#include <stdio.h>
#include <stdarg.h>

#include "DebugLog.h"

FILE *hndl;
char *savedFilename;

void debuglog_init(char *filename)
{
    savedFilename = filename;
    hndl = fopen(savedFilename, "wt");
    fclose(hndl);
}

void debuglog_close(void)
{
    //fclose(hndl);
}

void debuglog_log(char* format, ...)
{
    hndl = fopen(savedFilename,"at");
    va_list argptr;
    va_start(argptr, format);
    vfprintf(hndl, format, argptr);
    va_end(argptr);
    fputc('\n',hndl);
    fclose(hndl);
}

ম্যাক্রোগুলি ব্যবহার করা

এটি ব্যবহার করতে, কেবল করুন:

DEBUGLOG_INIT("afile.log");

লগ ফাইলে লিখতে, কেবল করুন:

DEBUGLOG_LOG(1, "the value is: %d", anint);

এটি বন্ধ করতে, আপনি:

DEBUGLOG_CLOSE();

যদিও বর্তমানে এটি প্রয়োজনীয় নয়, প্রযুক্তিগতভাবে বলছি, কারণ এটি কিছুই করে না। আমি এখনও এখনই বন্ধ ব্যবহার করছি, তবে আমি কীভাবে এটি কাজ করে সে সম্পর্কে আমার মন পরিবর্তন করি এবং লগিংয়ের বিবৃতিগুলির মধ্যে ফাইলটি উন্মুক্ত রাখতে চাই।

তারপরে, আপনি যখন ডিবাগ প্রিন্টিং চালু করতে চান, কেবলমাত্র শিরোনাম ফাইলটিতে প্রথম # ডিফাইনটি সম্পাদনা করুন, উদাহরণস্বরূপ

#define DEBUG 1

লগিং স্টেটমেন্টগুলি কোনও কিছুর সাথে সংকলন করার জন্য, করুন

#define DEBUG 0

আপনার যদি ঘন ঘন নির্বাহিত কোডের টুকরো (অর্থাত্‍ একটি উচ্চ স্তরের বিশদ) থেকে তথ্য প্রয়োজন হয় তবে আপনি লিখতে চাইতে পারেন:

 DEBUGLOG_LOG(3, "the value is: %d", anint);

আপনি যদি DEBUG 3 থেকে সংজ্ঞায়িত করেন তবে লগিং স্তর 1, 2 এবং 3 সংকলন করুন। যদি আপনি এটি 2 এ সেট করেন তবে আপনি লগিং স্তর 1 এবং 2 পাবেন you আপনি যদি এটি 1 এ সেট করেন তবে আপনি কেবল লগিং স্তরের 1 বিবৃতি পাবেন।

করণীয় লুপ হিসাবে, যেহেতু এটি কোনও একক ফাংশন বা কিছুইতে মূল্যায়ন করে না, যদি একটি আইএফ স্টেটমেন্টের পরিবর্তে লুপটির প্রয়োজন হয় না। ঠিক আছে, সি ++ আইও এর পরিবর্তে সি ব্যবহার করার জন্য আমাকে ক্যাজিট করুন (এবং কিউটির কিউস্ট্রিং :: আর্গ () কিউটিতে থাকাকালীন ভেরিয়েবলগুলিকে সুরক্ষিত করার একটি নিরাপদ উপায় - এটি বেশ চতুর, তবে আরও কোড লাগে এবং বিন্যাসের ডকুমেন্টেশন যেমন সজ্জিত হয় না তেমন এটি যেমনটি হতে পারে - তবে এখনও আমি এর চেয়ে বেশি কেসগুলি খুঁজে পেয়েছি) তবে আপনি নিজের পছন্দমতো .cpp ফাইলটিতে যে কোনও কোড রাখতে পারেন। এটি একটি শ্রেণিও হতে পারে, তবে তারপরে আপনাকে এটিকে তাত্ক্ষণিকভাবে চালিয়ে নেওয়া এবং এটি চালিয়ে যাওয়া, বা একটি নতুন () করা এবং এটি সঞ্চয় করা দরকার। এইভাবে, আপনি কেবল # অন্তর্ভুক্ত করুন, ইআরআই ছেড়ে দিন এবং sourceচ্ছিকভাবে আপনার উত্সটিতে বিবৃতি বন্ধ করুন এবং আপনি এটি ব্যবহার শুরু করতে প্রস্তুত। এটি খুব সূক্ষ্ম শ্রেণি তৈরি করবে, তবে আপনি যদি এত ঝোঁক হন।

আমি এর আগে অনেকগুলি সমাধান দেখেছি, তবে আমার মানদণ্ডগুলির সাথে এটির মতো কোনওটিই উপযুক্ত নয়।

  1. আপনার পছন্দ মতো স্তরগুলি বাড়ানোর জন্য এটি বাড়ানো যেতে পারে।
  2. এটি মুদ্রণ না হলে কিছুই সংকলন করে।
  3. এটি সম্পাদনা করার এক সহজ জায়গায় IO কে কেন্দ্রিয় করে তুলেছে।
  4. এটি নমনীয়, প্রিন্টফ বিন্যাস ব্যবহার করে।
  5. আবার এটি ডিবাগের রানগুলিকে কমিয়ে দেয় না, যেখানে সর্বদা-সংকলনকারী ডিবাগ প্রিন্টগুলি সর্বদা ডিবাগ মোডে কার্যকর করা হয়। আপনি যদি কম্পিউটার বিজ্ঞান করছেন, এবং তথ্য প্রক্রিয়াকরণ লেখার পক্ষে সহজ না হন তবে আপনি নিজেকে সিপিইউ-গ্রাহক সিমুলেটর চালিয়ে দেখতে পারেন, উদাহরণস্বরূপ, যেখানে কোনও ভেক্টরের জন্য নির্ধারিত পরিসীমা ছাড়াই ডিবাগার এটি থামিয়ে দেয়। এগুলি ডিবাগ মোডে ইতিমধ্যে অতিরিক্ত ধীরে ধীরে চলে। শত শত ডিবাগ প্রিন্টের বাধ্যতামূলক সম্পাদনা অগত্যা এই ধরণের রান আরও কমিয়ে দেবে। আমার জন্য এ জাতীয় রান অস্বাভাবিক নয়।

ভয়াবহভাবে তাৎপর্যপূর্ণ নয়, তবে অতিরিক্ত:

  1. আর্গুমেন্ট ছাড়াই মুদ্রণের জন্য এটি হ্যাকের প্রয়োজন নেই (যেমন DEBUGLOG_LOG(3, "got here!");); সুতরাং আপনাকে ব্যবহারের অনুমতি দেয়, উদাহরণস্বরূপ Qt এর নিরাপদ .arg () ফর্ম্যাটিং। এটি এমএসভিসিতে কাজ করে এবং সম্ভবত এটি জিসিসি। এটি এস ব্যবহার ##করে #define, যা অ-মানক, লেফলার উল্লেখ করেছেন, তবে এটি ব্যাপকভাবে সমর্থিত। (আপনি ##প্রয়োজনে এটি ব্যবহার না করার জন্য এটি পুনর্বিবেচনা করতে পারেন, তবে আপনাকে একটি হ্যাক ব্যবহার করতে হবে যেমন তিনি সরবরাহ করেন))

সতর্কতা: আপনি যদি লগিং স্তরের আর্গুমেন্ট সরবরাহ করতে ভুলে যান তবে এমএসভিসি অনিচ্ছাকৃতভাবে দাবি করে যে সনাক্তকারী সংজ্ঞায়িত হয়নি।

আপনি DEBUG ব্যতীত প্রিপ্রসেসর চিহ্নের নামটি ব্যবহার করতে চাইতে পারেন, কারণ কিছু উত্স সেই চিহ্নটিকেও সংজ্ঞায়িত করে (যেমন: বিল্ডিংয়ের ./configureজন্য প্রস্তুত করার জন্য কমান্ডগুলি ব্যবহার করে প্রগ্রেস )। আমি যখন এটি বিকাশ করেছি তখন এটি আমার কাছে স্বাভাবিক মনে হয়েছিল। আমি এটিকে এমন একটি অ্যাপ্লিকেশনটিতে তৈরি করেছি যেখানে ডিএলএল অন্য কোনও জিনিস দ্বারা ব্যবহৃত হচ্ছে এবং কোনও ফাইলে লগ প্রিন্টগুলি প্রেরণ করা আরও কন্টেন্ট; তবে এটিকে ভিপ্রিন্টফ () এ পরিবর্তন করা খুব ভাল কাজ করবে।

আমি আশা করি এটি আপনার অনেককেই ডিবাগ লগিংয়ের সর্বোত্তম উপায়ে নির্ধারণ সম্পর্কে শোক রক্ষা করতে পারে; বা আপনাকে পছন্দ করতে পারে এমন একটি দেখায়। আমি কয়েক দশক ধরে অর্ধ-হৃদয় দিয়ে এটিকে বের করার চেষ্টা করছি। এমএসভিসি 2012 এবং 2015 এ কাজ করে এবং সম্ভবত এটি জিসিসি তে; পাশাপাশি সম্ভবত আরও অনেকের সাথে কাজ করছি, তবে আমি এটি তাদের উপর পরীক্ষা করি নি।

আমিও বোঝাতে চাইছি এটিও এক দিনের স্ট্রিমিং সংস্করণ।

দ্রষ্টব্য: লেফ্লারের কাছে ধন্যবাদ, যিনি আমাকে আন্তরিকভাবে স্ট্যাক ওভারফ্লোয়ের জন্য আমার বার্তাটিকে আরও ভালভাবে ফর্ম্যাট করতে সহায়তা করেছেন।


2
আপনি বলছেন " if (DEBUG)রানটাইমের সময় কয়েক ডজন বা কয়েকশ বিবৃতি কার্যকর করা, যা অনুকূলিত হয় না" - যা উইন্ডমিলসে ঝুঁকছে । সিস্টেম আমি বর্ণনা সমগ্র বিন্দু যে কোড কম্পাইলার দ্বারা পরীক্ষা করা হয় হয় (গুরুত্বপূর্ণ স্বয়ংক্রিয়, এবং - কোন বিশেষ বিল্ড প্রয়োজন) কিন্তু ডিবাগ কোড আদৌ উত্পন্ন করা হয় না কারণ এটি হয় আউট অপ্টিমাইজ (তাই সেখানে শূন্য রানটাইম প্রভাব কোড আকার বা কার্য সম্পাদন কারণ কোড রানটাইমটিতে উপস্থিত নেই)।
জোনাথন লেফলার

জোনাথন লেফলার: আমার ভুল শব্দটির প্রতিশ্রুতি দেওয়ার জন্য থেক্স। আমি আমার চিন্তাভাবনাগুলিকে আমার আঙ্গুলের চেয়ে দ্রুত দৌড়তে দিয়েছি, এটি শেষ হয়ে খুব আনন্দিত। আমি "... 1) দিয়ে আমার আপত্তিগুলি সংশোধন করেছি আপনার অপ্টিমাইজড পাওয়ার জন্য আপনার অবশ্যই তাদের উপর আস্থা রাখতে হবে, যা আপনার কাছে পর্যাপ্ত অনুকূলিতকরণের মাত্রা থাকলে অবশ্যই ঘটতে হবে। ২) তবুও, আপনি যদি অপ্টিমাইজেশান সহ একটি প্রকাশনা সংকলন করেন তবে তারা তা করবে না পরীক্ষার উদ্দেশ্যে বন্ধ করে দেওয়া হয়েছে; এবং সম্ভবত তারা ডিবাগের সময় মোটেও তা করবে না - যার ফলে রানটাইমের সময় কয়েক ডজন বা কয়েকশ '' if (DEBUG) 'বিবৃতি কার্যকর করা হবে - যার ফলে আপনার এক্সিকিউটেবল বা ডিএল আকার এবং মৃত্যুদন্ডের সময় বৃদ্ধি পাবে। "
কোডলুকার

আমার যে গুরুত্বপূর্ণ কাজটি করছে তা করার জন্য আপনার ডিবাগ স্তর থাকতে হবে। যদিও আমার প্রায়শই তাদের প্রচুর পরিমাণে চালু হওয়ার প্রয়োজন হয় না, কিছু সাধারণ অ্যাপ্লিকেশন সাধারণ "# ডেফাইন DEBUG 3" দিয়ে সময়-সমালোচনামূলক লুপ সম্পর্কে দুর্দান্ত স্তরের বিশদ পেতে সক্ষম হয়ে সত্যই উপকৃত হয় এবং তারপরে ফিরে যেতে পারে to "# ডেফাইন DEBUG 1" এর সাথে অনেক কম ভার্বোজের তথ্য। আমার কখনও কখনও তিনটি স্তরের বেশি প্রয়োজন হয় নি এবং এভাবে আমার কমপক্ষে প্রায় 1/3 অংশ আগে থেকেই মুক্তি পেতে প্রস্তুত করা হয়েছে। আমি যদি সম্প্রতি স্তর 3 ব্যবহার করেছি তবে তারা সম্ভবত সব কিছু করে।
কোডলকার 18

YMMV। আমি যে আধুনিক সিস্টেমটি দেখিয়েছি তা ডিবাগ স্তরের গতিশীল (রানটাইম) সেটিং সমর্থন করে, তাই আপনি রানটাইমে কতটা ডিবাগ উত্পাদিত হবে তা আপনি প্রোগ্রামিকভাবে সিদ্ধান্ত নিতে পারেন। আমি সাধারণত 1-9 স্তরগুলি ব্যবহার করি, যদিও এর কোনও উচ্চতর সীমা নেই (বা নিম্ন সীমা; ডিফল্ট স্তরটি 0 থাকে যা সাধারণত বন্ধ থাকে, তবে যদি যথাযথভাবে সক্রিয় বিকাশের সময় স্পষ্টভাবে অনুরোধ করা যায় - এটি দীর্ঘমেয়াদী কাজের জন্য উপযুক্ত নয়)। আমি 3 এর একটি ডিফল্ট স্তর বেছে নিয়েছি; জিনিস সুর করা যেতে পারে। এটি আমাকে অনেক নিয়ন্ত্রণ দেয়। নিষ্ক্রিয় অবস্থায় আপনি যদি সত্যিই ডিবাগ কোডটি পরীক্ষা করতে না চান তবে বিকল্পটি পরিবর্তন করুন ((void)0)- এটি সহজ।
জোনাথন লেফলার

1
আহা। এটি পুরো জিনিসটি পড়তে সহায়তা করত। এটি একটি বরং দীর্ঘ পোস্ট। আমি মনে করি এটি এ পর্যন্ত প্রয়োজনীয় পয়েন্ট পেয়েছে। এটি আপনার মত, আমার মতো, সমস্ত ডিবাগ প্রিন্টগুলি সংকলন করতে বা সংকলন করতে ব্যবহৃত হতে পারে এবং স্তরগুলিকে সমর্থন করতে পারে; যদিও স্বীকার করা হয়েছে, আপনার ডিবাগ চলাকালীন কোনও ব্যয় - আপনার যে স্তরগুলি আপনি ব্যবহার করছেন না তা সংকলন করতে পারে।
কোডলকার 18

0

আমি বিশ্বাস করি থিমের এই প্রকরণটি বিভাগ অনুসারে পৃথক ম্যাক্রোর নাম ছাড়াই ডিবাগ বিভাগগুলি দেয়।

আমি এই আরডিনো প্রকল্পে এই প্রকরণটি ব্যবহার করেছি যেখানে প্রোগ্রাম স্পেসটি 32K এবং গতিশীল মেমরি 2K এর মধ্যে সীমাবদ্ধ। ডিবাগ স্টেটমেন্ট এবং ট্রেস ডিবাগ স্ট্রিংগুলির সংযোজন দ্রুত স্থান ব্যবহার করে। সুতরাং প্রতিটি বার কোড তৈরি হওয়ার সাথে সাথে সংকলনের সময় অন্তর্ভুক্ত থাকা ডিবাগ ট্রেসকে সীমাবদ্ধ করতে সক্ষম হওয়া জরুরী।

debug.h

#ifndef DEBUG_H
#define DEBUG_H

#define PRINT(DEBUG_CATEGORY, VALUE)  do { if (DEBUG_CATEGORY & DEBUG_MASK) Serial.print(VALUE);} while (0);

#endif

কল .cpp ফাইল

#define DEBUG_MASK 0x06
#include "Debug.h"

...
PRINT(4, "Time out error,\t");
...
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.