C++에서의 디버깅 매크로
C에서 DEBUG 매크로가 발견되어 매우 마음에 듭니다.
#ifdef DEBUG_BUILD
# define DEBUG(x) fprintf(stderr, x)
#else
# define DEBUG(x) do {} while (0)
#endif
C++의 아날로그는 다음과 같습니다.
#ifdef DEBUG_BUILD
# define DEBUG(x) cerr << x
#else
# define DEBUG(x) do {} while (0)
#endif
- 두 번째 코드 스니펫은 C의 코드 스니펫과 유사합니까?
- C++의 디버깅 매크로 중에서 마음에 드는 것이 있습니까?
EDIT : "디버깅 매크로"란 "디버깅 모드에서 프로그램을 실행할 때 편리할 수 있는 매크로"를 의미합니다.
두 번째 코드 스니펫은 C의 코드 스니펫과 유사합니까?
체로로그그그그그더 강력합니다.<<
내 - 하면 C 의 수 있습니다.반면에, 사람들이 논쟁에 세미콜론을 포함시킴으로써 그것을 남용할 가능성은 희박하다. 콜도 있습니다. 이걸 blockdo block에
#define DEBUG(x) do { std::cerr << x; } while (0)
마음에 드는 C++ 디버깅 매크로가 있나요?
저는 위의 것이 마음에 들어서 자주 사용하고 있습니다.내 무수술은 보통 그냥 읽기만 해
#define DEBUG(x)
컴파일러 최적화에도 같은 효과가 있습니다.다음 @Tony D에 의한 코멘트는 맞지만 일부 구문 오류가 검출되지 않을 수 있습니다.
런타임 체크도 포함하여 디버깅플래그의 형식을 지정할 수 있습니다.@Tony D가 상기시켰듯이, 엔들(Endl)이 있는 것도 도움이 됩니다.
#define DEBUG(x) do { \
if (debugging_enabled) { std::cerr << x << std::endl; } \
} while (0)
다음과 같은 표현도 인쇄하고 싶을 때가 있습니다.
#define DEBUG2(x) do { std::cerr << #x << ": " << x << std::endl; } while (0)
에 따라서는, 「마크로」라고 하는 것도 .__FILE__
,__LINE__
★★★★★★★★★★★★★★★★★」__func__
단, 이것들은 단순한 디버깅매크로가 아닌 어설션인 경우가 많습니다.
여기 내가 제일 좋아하는 게 있어
#ifdef DEBUG
#define D(x) x
#else
#define D(x)
#endif
매우 편리하고, 깨끗한 코드(중요한 릴리스 모드에서는 고속)를 실현합니다.
★★★#ifdef DEBUG_BUILD
over (code of 는 꽤 몇 의 행을 ('debug related blocks code')로.D()
.
사용방법:
D(cerr << "oopsie";)
그래도 너무 못생기거나 이상하거나 길면
#ifdef DEBUG
#define DEBUG_STDERR(x) (std::cerr << (x))
#define DEBUG_STDOUT(x) (std::cout << (x))
//... etc
#else
#define DEBUG_STDERR(x)
#define DEBUG_STDOUT(x)
//... etc
#endif
(사용하지 않는 것이 좋습니다.using namespace std;
using std::cout; using std::cerr;
은은 、 도도))은각 )
「디버깅」을 생각하고 있을 때는, stderr에 인쇄하는 것 이상의 작업을 실시할 필요가 있는 경우가 있습니다.창의력을 발휘하여 프로그램 내의 가장 복잡한 상호작용에 대한 통찰력을 제공하는 구성을 구축할 수 있습니다.또한 디버깅 인스트루먼테이션에 의해 방해받지 않고 매우 효율적인 버전의 구축으로 신속하게 전환할 수 있습니다.
예를 들어, 최근 프로젝트 중 하나에서 디버깅 전용 블록이 하나 있었는데, 이 블록은 다음과 같습니다.FILE* file = fopen("debug_graph.dot");
데이터 구조 내의 큰 트리를 시각화하기 위해 도트 형식의 그래프와 호환되는 그래프를 계속 내보냈습니다.더욱 쿨한 것은 OS X Graphviz 클라이언트가 변경 시 디스크에서 파일을 자동으로 읽기 때문에 프로그램이 실행될 때마다 그래프가 새로 고쳐진다는 것입니다.
디버깅 전용 멤버와 함수로 클래스/구조를 확장하는 것도 특히 좋아합니다.이를 통해 버그를 추적하는 데 도움이 되는 기능 및 상태를 구현할 수 있습니다.또한 디버깅매크로로 둘러싸인 다른 모든 것과 마찬가지로 빌드 파라미터를 전환하여 삭제할 수 있습니다.주정부 업데이트 때마다 구석구석 사건을 꼼꼼히 체크하는 거대한 루틴? 때리다D()
하는 것을 삭제해 주세요.-DDEBUG
빌드 스크립트(릴리스용 빌드)로부터, 유닛이나 그 외의 것을 위해서, 즉시 재활성화할 수 있습니다.
이 개념의 (어느 정도 지나치게 열성적인) 사용을 설명하기 위해 크고 다소 완전한 예를 다음에 제시하겠습니다.
#ifdef DEBUG
# define D(x) x
#else
# define D(x)
#endif // DEBUG
#ifdef UNITTEST
# include <UnitTest++/UnitTest++.h>
# define U(x) x // same concept as D(x) macro.
# define N(x)
#else
# define U(x)
# define N(x) x // N(x) macro performs the opposite of U(x)
#endif
struct Component; // fwd decls
typedef std::list<Component> compList;
// represents a node in the graph. Components group GNs
// into manageable chunks (which turn into matrices which is why we want
// graph component partitioning: to minimize matrix size)
struct GraphNode {
U(Component* comp;) // this guy only exists in unit test build
std::vector<int> adj; // neighbor list: These are indices
// into the node_list buffer (used to be GN*)
uint64_t h_i; // heap index value
U(int helper;) // dangling variable for search algo to use (comp node idx)
// todo: use a more space-efficient neighbor container?
U(GraphNode(uint64_t i, Component* c, int first_edge):)
N(GraphNode(uint64_t i, int first_edge):)
h_i(i) {
U(comp = c;)
U(helper = -1;)
adj.push_back(first_edge);
}
U(GraphNode(uint64_t i, Component* c):)
N(GraphNode(uint64_t i):)
h_i(i)
{
U(comp=c;)
U(helper=-1;)
}
inline void add(int n) {
adj.push_back(n);
}
};
// A component is a ugraph component which represents a set of rows that
// can potentially be assembled into one wall.
struct Component {
#ifdef UNITTEST // is an actual real struct only when testing
int one_node; // any node! idx in node_list (used to be GN*)
Component* actual_component;
compList::iterator graph_components_iterator_for_myself; // must be init'd
// actual component refers to how merging causes a tree of comps to be
// made. This allows the determination of which component a particular
// given node belongs to a log-time operation rather than a linear one.
D(int count;) // how many nodes I (should) have
Component(): one_node(-1), actual_component(NULL) {
D(count = 0;)
}
#endif
};
#ifdef DEBUG
// a global pointer to the node list that makes it a little
// easier to reference it
std::vector<GraphNode> *node_list_ptr;
# ifdef UNITTEST
std::ostream& operator<<(std::ostream& os, const Component& c) {
os << "<s=" << c.count << ": 1_n=" << node_list_ptr->at(c.one_node).h_i;
if (c.actual_component) {
os << " ref=[" << *c.actual_component << "]";
}
os << ">";
return os;
}
# endif
#endif
합니다.#ifdef
가독성이 다소 향상되기 때문에 조건이 충족됩니다.대블록의 경우 극히 짧은 매크로를 사용하는 것이 오히려 방해가 됩니다.
「 」의 N(x)
macro must exist는 unit-interval이 디세이블일 때 추가할 항목을 지정하는 것입니다.
이 파트에서는:
U(GraphNode(uint64_t i, Component* c, int first_edge):)
N(GraphNode(uint64_t i, int first_edge):)
이런 말을 할 수 있으면 좋을 텐데
GraphNode(uint64_t i, U(Component* c,) int first_edge):
그러나 콤마는 프리프로세서 구문의 일부이기 때문에 사용할 수 없습니다.쉼표를 생략하면 C++ 구문이 비활성화됩니다.
디버깅용으로 컴파일되지 않은 경우에 사용할 추가 코드가 있는 경우 이러한 유형의 대응 역디버깅 매크로를 사용할 수 있습니다.
이 코드가 '진짜 좋은 코드'의 예는 아닐지 모르지만매크로의 교묘한 어플리케이션으로 달성할 수 있는 것 중 몇 가지를 나타내고 있습니다.이것들에 대해 훈련을 계속한다고 해서 반드시 나쁜 것만은 아닙니다.
나는 방금 이 보석을 우연히 발견했다.do{} while(0)
이 매크로에 있는 모든 화려함도 정말 원하는군요!
이 예에서 C++ 코드를 개선하기 위해 할 수 있는 몇 가지 현명한 방법에 대한 통찰력을 얻을 수 있기를 바랍니다.무슨 일이 일어나고 있는지 모를 때 다시 코드를 작성하기보다는 코드를 작성하는 동안 계측하는 것이 매우 중요합니다.하지만 항상 견고하게 하는 것과 제시간에 완료시키는 것 사이에서 균형을 이루어야 합니다.
추가 디버깅 빌드 건전성 검사는 유닛 테스트와 마찬가지로 툴박스의 다른 툴이라고 생각합니다.유닛 테스트에 온전성 체크 로직을 도입해 실장으로부터 격리하는 것이 아니라 실장에 포함되어 자유롭게 조작할 수 있는 경우, 체크 기능을 유효하게 해, 만일의 경우에 실행할 수 있기 때문에, 완전한 테스트가 필요 없기 때문에, 한층 더 강력해질 가능성이 있다고 생각합니다.
저는 다음 마이크로 사용해요.
#if DEBUG
#define LOGE2(x,y) std::cout << "ERRO : " << "[" << __FILE__ << "][" << __FUNCTION__ << "][Line " << __LINE__ << "] " << x <<":"<< y <<std::endl;
#define LOGI2(x,y) std::cout << "INFO : " << "[" << __FILE__ << "][" << __FUNCTION__ << "][Line " << __LINE__ << "] " << x <<":"<< y << std::endl;
#define LOGD2(x,y) std::cout << "DEBG : " << "[" << __FILE__ << "][" << __FUNCTION__ << "][Line " << __LINE__ << "] " << x <<":"<< y << std::endl;
#define LOGE(x) std::cout << "ERRO : " << "[" << __FILE__ << "][" << __FUNCTION__ << "][Line " << __LINE__ << "] " << x << std::endl;
#define LOGI(x) std::cout << "INFO : " << "[" << __FILE__ << "][" << __FUNCTION__ << "][Line " << __LINE__ << "] " << x << std::endl;
#define LOGD(x) std::cout << "DEBG : " << "[" << __FILE__ << "][" << __FUNCTION__ << "][Line " << __LINE__ << "] " << x << std::endl;
#else
#define LOGE2(x,y) NULL
#define LOGI2(x,y) NULL
#define LOGD2(x,y) NULL
#define LOGE(x) NULL
#define LOGI(x) NULL
#define LOGD(x) NULL
#endif
용도:
LOGE("ERROR.");
LOGE2("ERROR1","ERROR2");
이것은 현재 사용하고 있는 로그 매크로입니다.
#ifndef DEBUG
#define DEBUG 1 // set debug mode
#endif
#if DEBUG
#define log(...) {\
char str[100];\
sprintf(str, __VA_ARGS__);\
std::cout << "[" << __FILE__ << "][" << __FUNCTION__ << "][Line " << __LINE__ << "] " << str << std::endl;\
}
#else
#define log(...)
#endif
사용방법:
log(">>> test...");
출력:
xxxx/proj.ios_mac/Classes/IntroScene.cpp][gotoNextScene][Line 58] >>> test...
모든 응답에 대한 부록으로 다음과 같은 것이 있습니다.
는 개인적으로 절대 .DEBUG
디버깅 릴리스 하기 위해 "를 사용합니다.NDEBUG
릴리스 빌드를 정의해야 합니다.assert()
콜을 사용합니다.assert()
'''가) 않은 매크로를 더할 필요가 또, 「!」라고 하는 경우에 할 수 있습니다.DEBUG
★★★★★★★★★★★★★★★★★」NDEBUG
을 사용하다
질문 1] 답은 '그렇다'입니다.메시지를 표준 오류 스트림으로 출력합니다.
질문 2] 많이 있어요.나의 가장 좋아하는 것은
#define LOG_ERR(...) fprintf(stderr, __VA_ARGS__)
이를 통해 임의의 수의 변수를 디버깅메시지에 포함할 수 있습니다.
템플릿 「Variadic」을 한 제입니다.print
★★★★
template<typename... ArgTypes>
inline void print(ArgTypes... args)
{
// trick to expand variadic argument pack without recursion
using expand_variadic_pack = int[];
// first zero is to prevent empty braced-init-list
// void() is to prevent overloaded operator, messing things up
// trick is to use the side effect of list-initializer to call a function
// on every argument.
// (void) is to suppress "statement has no effect" warnings
(void)expand_variadic_pack{0, ((cout << args), void(), 0)... };
}
#ifndef MYDEBUG
#define debug_print(...)
#else
#define debug_print(...) print(__VA_ARGS__)
#endif
가 만든 입니다.debug_print
실행 시 출력할 출력 종류를 선택할 수 있는 디버깅레벨을 받아들이는 바리에딕템플릿 함수:
template<typename... ArgTypes>
inline void debug_print(debug::debug level, ArgTypes... args)
{
if(0 != (debug::level & level))
print(args...);
}
해 주세요.print
함수가 Visual Studio 2013 Preview에 충돌합니다(RC를 테스트하지 않았습니다).에서는) 에서 (Windows에서) (Windows에서보다).ostream
""를 오버로드한 "operator<<
.
임시로 도 있습니다.stringstream
에 inside inside inside print
의 typesafe를 경우)printf
를 .__LINE__
,__FILE__
코드 내의 출력원이 어디인지를 나타내는 인수로서 같은 변수명을 여러 장소에 인쇄하는 것은 드문 일이 아니기 때문에,fprintf(stderr, "x=%d", x);
10줄 아래쪽에 같은 것을 하나 더 추가해도 큰 의미가 없습니다.
또, 특정의 기능을 덮어쓰고, 그 기능을 호출한 장소(메모리 할당등)를 보존하는 매크로도 사용하고 있기 때문에, 나중에 유출된 기능을 특정할 수 있습니다.메모리 할당에 대해서는 C++에서는 조금 어렵습니다.새로운/삭제를 사용하는 경향이 있어 쉽게 교체할 수 없기 때문입니다.그러나 잠금/잠금 해제 조작과 같은 다른 리소스는 이 방법을 추적하는 데 매우 유용합니다.물론, 좋은 C++ 프로그래머처럼 구축/파괴를 사용하는 잠금 래퍼가 있다면 이를 컨스트럭터에 추가합니다.o 잠금을 취득하면 내부 구조에 파일/줄을 추가합니다.또한 잠금을 취득할 수 없는 경우에는 다른 장소에 보관되어 있는 위치를 확인할 수 있습니다.
로그는 아래 코드를 사용합니다.몇 가지 장점이 있습니다.
- 실행 시 켜거나 끌 수 있습니다.
- 특정 로그 수준에서 문장을 컴파일할 수 있습니다.를 들어, 저는 있습니다.
KIMI_PRIVATE
에 기록되고 있기 에서 컴파일합니다.macro의 경우, macro의 경우, macro의 경우, macro의 경우, macro의 경우, secret source 의 경우, scret 의 경우 등입니다.
이 패턴은 몇 년 동안 나에게 매우 도움이 되었다.주의: 글로벌이 존재합니다.logMessage
일반적으로 로그는 로그 스레드에 큐잉됩니다.
#define KIMI_LOG_INTERNAL(level,EXPR) \
if(kimi::Logger::loggingEnabled(level)) \
{ \
std::ostringstream os; \
os << EXPR; \
kimi::Logger::logMessage(level ,os.str()); \
} \
else (void) 0
#define KIMI_LOG(THELEVEL,EXPR) \
KIMI_LOG_INTERNAL(kimi::Logger::LEVEL_ ## THELEVEL,EXPR)
#define KIMI_ERROR(EXPR) KIMI_LOG(ERROR,EXPR)
#define KIMI_VERBOSE(EXPR) KIMI_LOG(VERBOSE,EXPR)
#define KIMI_TRACE(EXPR) KIMI_LOG(TRACE,EXPR)
#define KIMI_INFO(EXPR) KIMI_LOG(INFO,EXPR)
#define KIMI_PROFILE(EXPR) KIMI_LOG(TRACE,EXPR)
// Use KIMI_PRIVATE for sensitive tracing
//#if defined(_DEBUG)
# define KIMI_PRIVATE(EXPR) KIMI_LOG(PRIVATE,EXPR)
// #else
// # define KIMI_PRIVATE(EXPR) (void)0
// #endif
다른 답변에서 알 수 있듯이 많은 답변이 있습니다.변수 개수의 인수를 허용하고 인수 이름을 인쇄하며 줄바꿈을 포함하는 것이 마음에 듭니다.
void debug_print() { std::cerr << std::endl; }
template <typename Head, typename... Tail>
void debug_print(Head H, Tail... T) {
std::cerr << ' ' << H;
debug_print(T...);
}
#ifdef DEBUGFLAG
# define DEBUG(...) std::cerr << "dbg (" << #__VA_ARGS__ << "):", \
debug_print(__VA_ARGS__)
#else
# define DEBUG(...) do {} while(0)
#endif
대부분의 설명은 이 답변과 동일하지만, 여러 변수를 다른 매크로 없이 한 줄에 디버깅하여 인쇄할 때 템플릿을 추가하면 단순해집니다.
언급URL : https://stackoverflow.com/questions/14251038/debug-macros-in-c
'sourcecode' 카테고리의 다른 글
서브디렉토리에서 Vue.js 웹팩 프로젝트를 처리하는 방법 (0) | 2022.08.12 |
---|---|
새 텍스트 상자 Vue3을 추가할 번호를 입력합니다. (0) | 2022.08.10 |
브라우저 콘솔에서 VueJs $watch 트리거가 작동하지 않음 (0) | 2022.08.10 |
vuej에서 추가 버튼 로드 (0) | 2022.08.10 |
Nuxt store getter가 작동하지 않습니다. 페이로드에 지정된 ID가 Integer + Error가 아닙니다. [vuex] 변환 핸들러 외부의 vuex 스토어 상태를 변환하지 마십시오. (0) | 2022.08.10 |