debrel
Я тоже был когда-то не уверен: конвертер комментариев влияет на Основы разработки?? Гмм... А ведь влияет!
И речь пойдет об Удивительной находке для всех промышленных языков программирования. Вы не ослышались: для всех!
С уважением, Сергей Деревяго.
Ведь оно так и есть! В мире C/C++. Посредством допотопного assert()
-а.
Почему ж его нет у других?! А на то есть причины:
assert()
и удивительно полезен, но там все сделано через C препроцессор.
Но как вы уже поняли, можно и без него. Тот кто нам мешает, тот нам поможет.
А начнем мы с примера реального кода:
#ifndef NDEBUG struct Debug { mutex mtx; int_map<uint32_t, uint32_t> allocated; Debug() {} Debug(const int_map<uint32_t, uint32_t>* a) : allocated(a) {} }; #endif void off_pool::free(offset off, uint32_t sz) { using namespace off_pool_cpp; #ifndef NDEBUG { auto dbg=(Debug*)debug; lock_guard<mutex> lock(dbg->mtx); int pos=dbg->allocated.find(off); assert(pos!=-1); assert(*dbg->allocated.pval(pos)==sz); dbg->allocated.erase(off); } #endif uint32_t asz=toAsz(sz); // ... } |
Это классика жанра и здесь все очень просто: в Release конфигурации строки кода между #ifndef NDEBUG
и #endif
полностью исчезают, и мы получаем идеальный билд. Без единого лишнего байта!
Но идентичного результата можно добиться и с помощью комментариев:
//D5|struct Debug { //D5| mutex mtx; //D5| int_map<uint32_t, uint32_t> allocated; //D5| //D5| Debug() {} //D5| Debug(const int_map<uint32_t, uint32_t>* a) : allocated(a) {} //D5|}; void off_pool::free(offset off, uint32_t sz) { using namespace off_pool_cpp; //D5| { //D5| auto dbg=(Debug*)debug; //D5| lock_guard<mutex> lock(dbg->mtx); //D5| //D5| int pos=dbg->allocated.find(off); //D5| perm_assert(pos!=-1); //D5| perm_assert(*dbg->allocated.pval(pos)==sz); //D5| dbg->allocated.erase(off); //D5| } uint32_t asz=toAsz(sz); // ... } |
Да, можно. И что же?
А то, что в случае Debug конфигурации, все эти едкие комментарии потребно выставить на мороз! И вот тут уже нужен DebRel -- один запуск программы и опа:
struct Debug { //D5| mutex mtx; //D5| int_map<uint32_t, uint32_t> allocated; //D5| //D5| Debug() {} //D5| Debug(const int_map<uint32_t, uint32_t>* a) : allocated(a) {} //D5| }; //D5| void off_pool::free(offset off, uint32_t sz) { using namespace off_pool_cpp; { //D5| auto dbg=(Debug*)debug; //D5| lock_guard<mutex> lock(dbg->mtx); //D5| //D5| int pos=dbg->allocated.find(off); //D5| perm_assert(pos!=-1); //D5| perm_assert(*dbg->allocated.pval(pos)==sz); //D5| dbg->allocated.erase(off); //D5| } //D5| uint32_t asz=toAsz(sz); // ... } |
Вся доступная диагностика у нас снова в бою!
debrel
debrel
? Она просто переставляет известные ей комментарии из начала строки в конец, тем самым включая и выключая помеченные вами блоки:
s1="строка включена"; //D5| //D6| s2="строка выключена"; |
А всего существует два десятка возможных вариантов: D0
- D9
и R0
- R9
. И вот так-то они работают:
RN
отменяет все остальные. Релиз -- эгоист!
DN
оставляет лишь строки от D0
до DN
. Вы задаете глубину отладки.
> debrel DebRel v1.0 (2025-06-03), Debug/Release comment converter, freeware Copyright (c) Sergey P. Derevyago Usage: debrel [-c#] A file D0-5-10 [R5-20-30 D9-50-100 ...] debrel [-c#] R0|D5 file1 [file2 file3 ...] debrel [-c#] C|U file1 [file2 file3 ...] |
Пройдемся по пунктам:
//
. Используйте -c#
для Python.
file
блоки комментариев (в конец строки).
RN
.
DN
.
D5
по умолчанию. А D3
и D7
для поменьше/побольше отладки.
R0
по умолчанию. Но Release комментариев обычно не будет вообще.
Кроме нескольких версий Release -- а зачем? Дело в том, что и правда бывают варианты!
Вот возьмем, например, эту страшную функцию:
func rthash(buf []byte, seed uint64) uint64 { if len(buf) == 0 { return seed } len := len(buf) if goarch.PtrSize == 8 { return uint64(runtime_memhash(unsafe.Pointer(&buf[0]), uintptr(seed), uintptr(len))) } lo := runtime_memhash(unsafe.Pointer(&buf[0]), uintptr(seed), uintptr(len)) hi := runtime_memhash(unsafe.Pointer(&buf[0]), uintptr(seed>>32), uintptr(len)) return uint64(hi)<<32 | uint64(lo) } |
Она компилируется на 64- и 32-битную архитектуру одновременно и поэтому проверяет goarch.PtrSize
. И тут самое время подумать, что размер указателя нам известен на стадии сборки...
Сразу просятся R4
/R8
:
func rthash(buf []byte, seed uint64) uint64 { if len(buf) == 0 { return seed } len := len(buf) return uint64(runtime_memhash(unsafe.Pointer(&buf[0]), uintptr(seed), uintptr(len))) //R8| //R4| lo := runtime_memhash(unsafe.Pointer(&buf[0]), uintptr(seed), uintptr(len)) //R4| hi := runtime_memhash(unsafe.Pointer(&buf[0]), uintptr(seed>>32), uintptr(len)) //R4| return uint64(hi)<<32 | uint64(lo) } |
Хоть маленечко смысла в помойке!
Появился DebRel -- стало меньше зубовного скрежета!! То, что в C/C++ занимает секунды, теперь стало доступно для всех:
assert()
в важном месте? Напишите //D5| Аssert(...)
!
//D8| Dump(...)
.
R0
/R1
.
Никакая часть данного материала не может быть использована в коммерческих целях без письменного разрешения автора.