บทนำ

นักพัฒนามักพบว่าตนเองต้องการกลไกการบันทึกที่เชื่อถือได้เพื่อใช้ในการดีบัก อย่างไรก็ตาม การรักษาประสิทธิภาพของโค้ดในระหว่างการผลิตอาจเป็นเรื่องท้าทาย โดยเฉพาะเมื่อการบันทึกที่มีรายละเอียดมากอาจส่งผลกระทบต่อประสิทธิภาพ คำถามทั่วไปเกิดขึ้น: คุณจะสร้างฟังก์ชันที่ใช้สำหรับการดีบักซึ่งสนับสนุนรายการอาร์กิวเมนต์ตัวแปรคล้ายกับ printf() ได้อย่างไร?

ในบล็อกโพสต์นี้ เราจะสำรวจวิธีการที่ตรงไปตรงมาซึ่งใช้คำสั่งของโปรเซสเซอร์ใน C/C++ เพื่อสร้างฟังก์ชันการบันทึกที่สามารถลบออกในระหว่างการปรับแต่งประสิทธิภาพ ในขณะเดียวกันก็รักษาความยืดหยุ่นของข้อมูลนำเข้าได้

การสร้างฟังก์ชัน Debug Logging

ขั้นตอนที่ 1: กำหนดลายเซ็นฟังก์ชัน

เราต้องการให้ฟังก์ชันการบันทึกของเรารับสตริงรูปแบบและจำนวนอาร์กิวเมนต์ที่แตกต่างกัน ฟังก์ชันลายเซ็นแบบ printf ช่วยให้เราสามารถจัดรูปแบบสตริงได้อย่างไดนามิก ด้านล่างคือโครงสร้างกระดูกสันหลังพื้นฐานของฟังก์ชันที่ต้องการ:

void XTrace(LPCTSTR lpszFormat, ...);

ขั้นตอนที่ 2: การใช้ตัวแปรอาร์กิวเมนต์

เพื่อให้ได้ฟังก์ชันการทำงานของอาร์กิวเมนต์ตัวแปร เราสามารถใช้แมโคร va_list, va_start และ va_end ที่มีอยู่ในไลบรารีมาตรฐาน C สิ่งนี้ช่วยให้เราสามารถประมวลผลอาร์กิวเมนต์ที่ส่งไปยัง XTrace

นี่คือวิธีที่คุณสามารถนำไปใช้:

#include <stdio.h>

void XTrace(LPCTSTR lpszFormat, ...) {
    va_list args;
    va_start(args, lpszFormat);
    int nBuf;
    TCHAR szBuffer[512]; // คิดเกี่ยวกับการใช้การจัดสรรแบบไดนามิกแทน
    nBuf = _vsnprintf(szBuffer, 511, lpszFormat, args);
    ::OutputDebugString(szBuffer); 
    va_end(args);
}

ส่วนสำคัญของโค้ด:

  • va_list args: ใช้ในการจัดเก็บรายการอาร์กิวเมนต์
  • va_start(args, lpszFormat): ใช้ในการเริ่มต้น args เพื่อนำค่าอาร์กิวเมนต์หลัง lpszFormat
  • _vsnprintf: ฟังก์ชันนี้จัดรูปแบบสตริงโดยใช้รายการอาร์กิวเมนต์และเขียนไปยังบัฟเฟอร์
  • OutputDebugString: ส่งผลลัพธ์สตริงที่จัดรูปแบบไปยังหน้าต่างเอาต์พุตของดีบักเกอร์

ขั้นตอนที่ 3: การสร้างคอมไพล์เงื่อนไข

เพื่อให้แน่ใจว่าฟังก์ชันการดีบักจะถูกลบออกในระหว่างการปรับแต่งประสิทธิภาพ เราสามารถใช้คำสั่งโปรเซสเซอร์ โดยการกำหนดแมโครตามธงการดีบัก เราสามารถควบคุมได้ว่าฟังก์ชันการบันทึกของเราจะรวมอยู่ด้วยหรือไม่

การตั้งค่าสำหรับตัวอย่าง:

#ifdef _DEBUG
#define XTRACE XTrace
#else
#define XTRACE
#endif
  • แมโคร XTRACE จะชี้ไปยังฟังก์ชัน XTrace ที่แท้จริงเมื่อคอมไพล์ในโหมดดีบัก ในการปรับแต่งประสิทธิภาพ (เมื่อไม่กำหนด _DEBUG), XTRACE จะกลายเป็นคำสั่งว่าง ส่งผลให้ลบโค้ดบันทึกการดีบักออกไปอย่างมีประสิทธิภาพ

การรวมทุกอย่างเข้าด้วยกัน

นี่คือการนำไปใช้ทั้งหมดเพื่อความชัดเจน:

#include <stdio.h>
#include <stdarg.h>
#include <Windows.h> // หรือ <Linux/string.h> ขึ้นอยู่กับแพลตฟอร์ม

void XTrace0(LPCTSTR lpszText) {
    ::OutputDebugString(lpszText);
}

void XTrace(LPCTSTR lpszFormat, ...) {
    va_list args;
    va_start(args, lpszFormat);
    int nBuf;
    TCHAR szBuffer[512];
    nBuf = _vsnprintf(szBuffer, 511, lpszFormat, args);
    ::OutputDebugString(szBuffer);
    va_end(args);
}

#ifdef _DEBUG
#define XTRACE XTrace
#else
#define XTRACE
#endif

ตอนนี้คุณสามารถใช้แมโคร XTRACE ในโค้ดของคุณได้ดังนี้:

XTRACE("Warning: value %d > 3!\n", value);

สรุป

การสร้างฟังก์ชันการบันทึกที่ใช้สำหรับดีบักใน C/C++ ที่สามารถรับตัวแปรอาร์กิวเมนต์ไม่เพียง แต่สามารถทำได้ แต่ยังสามารถจัดการได้อย่างมีประสิทธิภาพโดยใช้คำสั่งโปรเซสเซอร์ เทคนิคนี้ช่วยให้โค้ดการผลิตของคุณสะอาดและมีประสิทธิภาพ

ตอนนี้คุณสามารถดีบักแอปพลิเคชันของคุณอย่างมีประสิทธิภาพโดยไม่กระทบต่อประสิทธิภาพในสภาพแวดล้อมการผลิต!