意圖通過封裝代碼以在輸出時提供更多信息。
代碼:
//More information when outputting in Debug mode
//<iomanip> setw setfill dec
//<typeinfo> typeid
//<sstream> stringstream
//<thread> this_thread
//<chrono> chrono
//<ctime>
#ifdef _DEBUG
#define TYPE(type, var) Type(#var, var, __LINE__, __FUNCTION__, #type)
template <typename T>
void Type(const char* varName, T var, int line, const char* functionName, const char* type) {
std::stringstream ss;
ss << type << " <==> [" << typeid(var).name() << "] ";
std::ios_base::fmtflags originalFlags = std::cout.flags();/*FORMAT FLAG*/\
/*auto now = std::chrono::system_clock::now();*//*TIME*/\
/*std::time_t timestamp = std::chrono::system_clock::to_time_t(now);*//*TIME*/\
/* std::cout << "\nTime taken at Total : " << duration.count() / 1000.0 << " millisecond" << std::endl;*//*TIME*/
std::cout.width(0);
std::cout << std::setfill(' ') << std::left << "TYPE "\
<< std::setw(50) << ss.str()/*TYPE*/\
<< " At " << std::setw(15) << functionName /*FUNCTION*/\
<< std::dec << ",line " << std::setw(5) << std::setfill('0') << std::right << line /*LINE*/\
/*<< "File: " << __FILE__ */ /*FILE*/\
/*<< ", Thread ID: " << std::this_thread::get_id() << ", "*//*THREAD*/\
<< std::endl; \
std::cout.flags(originalFlags);
}
#define LOG(var) Log(#var, var, __LINE__, __FUNCTION__)
template <typename T>
void Log(const char* varName, T var, int line, const char* functionName) {
std::stringstream ss;
ss << "[" << typeid(var).name() << "] " << varName << " = [" << var << "]";
std::ios_base::fmtflags originalFlags = std::cout.flags();/*FORMAT FLAG*/\
/*auto now = std::chrono::system_clock::now();*//*TIME*/\
/*std::time_t timestamp = std::chrono::system_clock::to_time_t(now);*//*TIME*/\
/* std::cout << "\nTime taken at Total : " << duration.count() / 1000.0 << " millisecond" << std::endl;*//*TIME*/
std::cout.width(0);
std::cout << std::setfill(' ') << std::left << "LOG "\
<< std::setw(50) << ss.str()/*TYPE*//*VARIABLE*//*VALUE*/\
<< " At " << std::setw(15) << functionName /*FUNCTION*/\
<< std::dec << ",line " << std::setw(5) << std::setfill('0') << std::right << line /*LINE*/\
/*<< "File: " << __FILE__ */ /*FILE*/\
/*<< ", Thread ID: " << std::this_thread::get_id() << ", "*//*THREAD*/\
<< std::endl; \
std::cout.flags(originalFlags);
}
#else
template <typename T>
void Type(const char* varName, T var, int line, const char* functionName) {}
template <typename T>
void Log(const char* varName, T var, int line, const char* functionName) {}
#endif
使用方式:
LOG(變量);
TYPE(變量的類型, 變量);
這個變量的類型,需要手動填入,填什麼輸出什麼。
範例輸入1:
LOG(20);
LOG(3.14158);
LOG('A');
LOG("Hello world");
LOG(false);
LOG(100000000000000000);
範例輸出1:
LOG [int] 20 = 20 At funcPart0 ,line 00069
LOG [double] 3.14158 = 3.14158 At funcPart0 ,line 00070
LOG [char] 'A' = A At funcPart0 ,line 00071
LOG [char const * __ptr64] "Hello world" = Hello worldAt funcPart0 ,line 00072
LOG [bool] false = 0 At funcPart0 ,line 00073
LOG [__int64] 100000000000000000 = 100000000000000000 At funcPart0 ,line 00074
範例輸入2:
int a = 30;
LOG(a);
long long ffffffffffffffffffffffffffffff = 1;
LOG(ffffffffffffffffffffffffffffff);
char c = 'a';
char* ptrC = &c;
LOG(ptrC);
LOG(&ptrC);
LOG(*&*&*&*(ptrC));
範例輸出2:
LOG [int] a = 30 At funcPart0 ,line 00065
LOG [__int64] ffffffffffffffffffffffffffffff = 1 At funcPart0 ,line 00067
LOG [char * __ptr64] ptrC = a昍昍昍昍昍昍昍昍昍昍昍昍昍昍昍昍昍怳? At funcPart0 ,line 00070
LOG [char * __ptr64 * __ptr64] &ptrC = 000000E89092F4C8 At funcPart0 ,line 00071
LOG [char] *&*&*&*(ptrC) = a At funcPart0 ,line 00072
(輸出第三行這個指針的內容有亂碼,只有第一字被寫入內容,畢竟是個char麻)
範例輸入3:
LOG(std::dec);
int a = 40;
TYPE(int, a);
std::ios_base::fmtflags ff;
ff = std::cout.flags();
TYPE(std::ios_base::fmtflags, ff);
範例輸出3:
LOG [class std::ios_base & __ptr64 (__cdecl*)(class std::ios_base & __ptr64)] std::dec = At funcPart0 ,line 00064
TYPE int <==> [int] At funcPart0 ,line 00067
TYPE std::ios_base::fmtflags <==> [int] At funcPart0 ,line 00071
以下是關於輸出3的解釋:
在xiosbase文件中第93行,可以看到fmtflag確實是int。
using fmtflags = int;
在ios文件第190行,可以看到std::dec函數,這是跟輸出流和調用慣例相關的底層函數實現,不必在意。
_EXPORT_STD inline ios_base& __CLRCALL_OR_CDECL dec(ios_base& _Iosbase) { // set basefield to dec
_Iosbase.setf(ios_base::dec, ios_base::basefield);
return _Iosbase;
}
在vcruntime文件第140行,macro __CLRCALL_OR_CDCEL被替換成了 __cdcel。
// Definitions of calling conventions used code sometimes compiled as managed
#if defined _M_CEE_PURE || defined MRTDLL
(條件編譯失敗)#define __CLRCALL_OR_CDECL __clrcall
(條件編譯失敗)#define __CLR_OR_THIS_CALL __clrcall
#else
#define __CLRCALL_OR_CDECL __cdecl
#define __CLR_OR_THIS_CALL
#endif
然後int就是int,這個應該沒問題。
代碼說明:
1.用macro替換成Type(#var, var, __LINE__, __FUNCTION__, #type)。
其中#var是第二個參數文字。二是第二個參數。三是行數。四是文件名。五是第一個參數的名。
2.調用Type或Log函數。
3.進入模板函數開始輸出。
結語:
我在玩和深挖代碼時,需要一個好的環境, 如果有一個模板可以複製貼上,那可以減低重複性的工作並提高效率,在此提供我的參考。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <iomanip>
#include <typeinfo>
#include <sstream>
#include <chrono>
//#include <thread>
//#include <ctime>
//More information when outputting in Debug mode
//<iomanip> setw setfill dec
//<typeinfo> typeid
//<sstream> stringstream
//<thread> this_thread
//<chrono> chrono
//<ctime>
#ifdef _DEBUG
#define TYPE(type, var) Type(#var, var, __LINE__, __FUNCTION__, #type)
template <typename T>
void Type(const char* varName, T var, int line, const char* functionName, const char* type) {
std::stringstream ss;
ss << type << " <==> [" << typeid(var).name() << "] ";
std::ios_base::fmtflags originalFlags = std::cout.flags();/*FORMAT FLAG*/\
/*auto now = std::chrono::system_clock::now();*//*TIME*/\
/*std::time_t timestamp = std::chrono::system_clock::to_time_t(now);*//*TIME*/\
/* std::cout << "\nTime taken at Total : " << duration.count() / 1000.0 << " millisecond" << std::endl;*//*TIME*/
std::cout.width(0);
std::cout << std::setfill(' ') << std::left << "TYPE "\
<< std::setw(50) << ss.str()/*TYPE*/\
<< " At " << std::setw(15) << functionName /*FUNCTION*/\
<< std::dec << ",line " << std::setw(5) << std::setfill('0') << std::right << line /*LINE*/\
/*<< "File: " << __FILE__ */ /*FILE*/\
/*<< ", Thread ID: " << std::this_thread::get_id() << ", "*//*THREAD*/\
<< std::endl; \
std::cout.flags(originalFlags);
}
#define LOG(var) Log(#var, var, __LINE__, __FUNCTION__)
template <typename T>
void Log(const char* varName, T var, int line, const char* functionName) {
std::stringstream ss;
ss << "[" << typeid(var).name() << "] " << varName << " = [" << var << "]";
std::ios_base::fmtflags originalFlags = std::cout.flags();/*FORMAT FLAG*/\
/*auto now = std::chrono::system_clock::now();*//*TIME*/\
/*std::time_t timestamp = std::chrono::system_clock::to_time_t(now);*//*TIME*/\
/* std::cout << "\nTime taken at Total : " << duration.count() / 1000.0 << " millisecond" << std::endl;*//*TIME*/
std::cout.width(0);
std::cout << std::setfill(' ') << std::left << "LOG "\
<< std::setw(50) << ss.str()/*TYPE*//*VARIABLE*//*VALUE*/\
<< " At " << std::setw(15) << functionName /*FUNCTION*/\
<< std::dec << ",line " << std::setw(5) << std::setfill('0') << std::right << line /*LINE*/\
/*<< "File: " << __FILE__ */ /*FILE*/\
/*<< ", Thread ID: " << std::this_thread::get_id() << ", "*//*THREAD*/\
<< std::endl; \
std::cout.flags(originalFlags);
}
#else
template <typename T>
void Type(const char* varName, T var, int line, const char* functionName) {}
template <typename T>
void Log(const char* varName, T var, int line, const char* functionName) {}
#endif
//
void funcPart0()
{
}
//
void funcPart1()
{
}
//
void funcPart2()
{
}
//
void funcPart3()
{
}
//
void funcPart4()
{
}
//
void funcPart5()
{
}
//
void funcPart6()
{
}
//
void funcPart7()
{
}
//
void funcPart8()
{
}
//
void funcPart9()
{
}
void doAllFuncPart(void (**f)())
{
for (int i = 0; i < 10; ++i)
{
f[i]();
}
}
int main() {
auto start_time = std::chrono::high_resolution_clock::now();
void (*funcPart[10])() = { funcPart0 ,funcPart1 ,funcPart2 ,funcPart3 ,funcPart4 ,funcPart5 ,funcPart6 ,funcPart7 ,funcPart8,funcPart9 };
doAllFuncPart(funcPart);
auto end_time = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time);
std::cout << "\nTime taken at Total : " << duration.count() / 1000.0 << " millisecond" << std::endl;
return 0;
}
註:我會回來更新函數,如果我找到更好的或是更新了函數,只會改最下面的代碼,所以範例可能會稍有不同。
2024/04/28 新的參考
新年新氣象,這都用上spdlog、catch2和分文件了了。
文件
funcPart_00_09.cpp文件
#include "funcPart_00_09.h"
void funcPart00()
{
}
void funcPart01()
{
}
void funcPart02()
{
}
void funcPart03()
{
}
void funcPart04()
{
}
void funcPart05()
{
}
void funcPart06()
{
}
void funcPart07()
{
}
void funcPart08()
{
}
void funcPart09()
{
}
funcPart_00_09.h文件
#ifndef FUNCPART_00_09_H
#define FUNCPART_00_09_H
#include "common.h"
void funcPart00();
void funcPart01();
void funcPart02();
void funcPart03();
void funcPart04();
void funcPart05();
void funcPart06();
void funcPart07();
void funcPart08();
void funcPart09();
#endif
此外還有
funcPart_10_19.h 到 funcPart_90_99.h
funcPart_10_19.cpp 到 funcPart_90_99.cpp。
main.cpp文件
#include "catch2/catch_amalgamated.hpp"
#include "common.h"
#include "funcPart_00_09.h"
#include "funcPart_10_19.h"
#include "funcPart_20_29.h"
#include "funcPart_30_39.h"
#include "funcPart_40_49.h"
#include "funcPart_50_59.h"
#include "funcPart_60_69.h"
#include "funcPart_70_79.h"
#include "funcPart_80_89.h"
#include "funcPart_90_99.h"
void doAllFuncPart(void (**f)(), int count)
{
for (int i = 0; i < count; ++i)
{
f[i]();
}
}
int main(int argc, char* argv[]) {
/*函數時間測量代碼*/
auto start_time = std::chrono::high_resolution_clock::now();
/*執行所有函數代碼*/
void (*funcPart[])() = {
funcPart00, funcPart01, funcPart02, funcPart03, funcPart04, funcPart05, funcPart06, funcPart07, funcPart08, funcPart09,
funcPart10, funcPart11, funcPart12, funcPart13, funcPart14, funcPart15, funcPart16, funcPart17, funcPart18, funcPart19,
funcPart20, funcPart21, funcPart22, funcPart23, funcPart24, funcPart25, funcPart26, funcPart27, funcPart28, funcPart29,
funcPart30, funcPart31, funcPart32, funcPart33, funcPart34, funcPart35, funcPart36, funcPart37, funcPart38, funcPart39,
funcPart40, funcPart41, funcPart42, funcPart43, funcPart44, funcPart45, funcPart46, funcPart47, funcPart48, funcPart49,
funcPart50, funcPart51, funcPart52, funcPart53, funcPart54, funcPart55, funcPart56, funcPart57, funcPart58, funcPart59,
funcPart60, funcPart61, funcPart62, funcPart63, funcPart64, funcPart65, funcPart66, funcPart67, funcPart68, funcPart69,
funcPart70, funcPart71, funcPart72, funcPart73, funcPart74, funcPart75, funcPart76, funcPart77, funcPart78, funcPart79,
funcPart80, funcPart81, funcPart82, funcPart83, funcPart84, funcPart85, funcPart86, funcPart87, funcPart88, funcPart89,
funcPart90, funcPart91, funcPart92, funcPart93, funcPart94, funcPart95, funcPart96, funcPart97, funcPart98, funcPart99,
};
int funcCount = sizeof(funcPart) / sizeof(funcPart[0]);
doAllFuncPart(funcPart, funcCount);
/*catch2代碼*/
// 初始化 Catch2 的 Session
Catch::Session session;
// 處理命令行參數
int result = session.applyCommandLine(argc, argv);
if (result != 0) { // 命令行參數錯誤
return result;
}
// 運行所有測試
int numFailed = session.run();
/*函數時間測量代碼*/
auto end_time = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time);
std::cout << "\nTime taken at Total : " << duration.count() / 1000.0 << " milliseconds" << std::endl;
/*catch2代碼*/
//返回失敗的測試數量
return numFailed;
}
catch_main.cpp文件,catch2去github抓。
#define CATCH_CONFIG_MAIN // 這行告訴 Catch 提供 main() 函數
#include "catch2/catch_amalgamated.hpp"
#include "catch2/catch_amalgamated.cpp"
common.h 通用工具文件
#ifndef COMMON_H
#define COMMON_H
#define _CRT_SECURE_NO_WARNINGS
#include <spdlog/spdlog.h>
#include <catch2/catch_amalgamated.hpp>
#include <iostream>
#include <iomanip>
#include <typeinfo>
#include <sstream>
#include <chrono>
#include <stdexcept>
//#include <thread>
//#include <ctime>
//More information when outputting in Debug mode
//<iomanip> setw setfill dec
//<typeinfo> typeid
//<sstream> stringstream
//<thread> this_thread
//<chrono> chrono
//<ctime>
#ifdef _DEBUG
#define TYPE(type, var) Type(#var, var, __LINE__, __FUNCTION__, #type)
template <typename T>
void Type(const char* varName, T var, int line, const char* functionName, const char* type) {
std::stringstream ss;
ss << type << " <==> [" << typeid(var).name() << "] ";
std::ios_base::fmtflags originalFlags = std::cout.flags();/*FORMAT FLAG*/\
/*auto now = std::chrono::system_clock::now();*//*TIME*/\
/*std::time_t timestamp = std::chrono::system_clock::to_time_t(now);*//*TIME*/\
/* std::cout << "\nTime taken at Total : " << duration.count() / 1000.0 << " millisecond" << std::endl;*//*TIME*/
std::cout.width(0);
std::cout << std::setfill(' ') << std::left << "TYPE "\
<< std::setw(50) << ss.str()/*TYPE*/\
<< " At " << std::setw(15) << functionName /*FUNCTION*/\
<< std::dec << ",line " << std::setw(5) << std::setfill('0') << std::right << line /*LINE*/\
/*<< "File: " << __FILE__ */ /*FILE*/\
/*<< ", Thread ID: " << std::this_thread::get_id() << ", "*//*THREAD*/\
<< std::endl; \
std::cout.flags(originalFlags);
}
#define LOG(var) Log(#var, var, __LINE__, __FUNCTION__)
template <typename T>
void Log(const char* varName, T var, int line, const char* functionName) {
std::stringstream ss;
ss << "[" << typeid(var).name() << "] " << varName << " = [" << var << "]";
std::ios_base::fmtflags originalFlags = std::cout.flags();/*FORMAT FLAG*/\
/*auto now = std::chrono::system_clock::now();*//*TIME*/\
/*std::time_t timestamp = std::chrono::system_clock::to_time_t(now);*//*TIME*/\
/* std::cout << "\nTime taken at Total : " << duration.count() / 1000.0 << " millisecond" << std::endl;*//*TIME*/
std::cout.width(0);
std::cout << std::setfill(' ') << std::left << "LOG "\
<< std::setw(50) << ss.str()/*TYPE*//*VARIABLE*//*VALUE*/\
<< " At " << std::setw(15) << functionName /*FUNCTION*/\
<< std::dec << ",line " << std::setw(5) << std::setfill('0') << std::right << line /*LINE*/\
/*<< "File: " << __FILE__ */ /*FILE*/\
/*<< ", Thread ID: " << std::this_thread::get_id() << ", "*//*THREAD*/\
<< std::endl; \
std::cout.flags(originalFlags);
}
#else
template <typename T>
void Type(const char* varName, T var, int line, const char* functionName) {}
template <typename T>
void Log(const char* varName, T var, int line, const char* functionName) {}
#endif
#endif // COMMON_H
把spdlog/include和catch2.h catch2.cpp放在third_party目錄下, 記得在visual studio 2022的VC++ 裡面的包含目錄加上$(SolutionDir)/third_party;,這樣能通過<>去包含,就這樣吧,之後幾天應該會把operator overloading的教學發上來。