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);
// ...
}
|
Вся доступная диагностика у нас снова в бою!
debreldebrel? Она просто переставляет узнаваемые комментарии из начала в конец строки, тем самым включая и выключая помеченные вами блоки:
s1="строка включена"; //D5| //D6| s2="строка выключена"; |
А всего существует два десятка Debug/Release вариантов и хреналеон дополнительных -- D0-D9/R0-R9 плюс особые Sxxx:
RN отменяет все остальные. Релиз -- эгоист!
DN оставляет лишь строки от D0 до DN. Вы задаете глубину отладки.
DN/RN конфигурации, возможно указать и специальные. С большой буквы S.
> debrel DebRel v1.2 (2025-12-10), Debug/Release comment converter, freeware Copyright (c) Sergey P. Derevyago Usage: debrel [-c#] -A -D0-5-10 [-~R5-20-30 ...] file debrel [-c#] -D5|-R0 [-Spec1 ...] file1 [file2 ...] debrel [-c#] -C|-U file1 [file2 ...] debrel /* ... */ -r path mask debrel /* ... */ -f files.txt |
Пройдемся по пунктам:
//. Используйте -c# для Python.
file блоки комментариев (в конец строки). Возможны инвертированные цели (-~R5-20-30).
DN. Возможны дополнительные цели (Sxxx).
RN. Возможны дополнительные цели (Sxxx).
D5 по умолчанию. А D3 и D7 для поменьше/побольше отладки.
R0 по умолчанию. Но 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. И тут самое время подумать, что размер указателя нам известен на стадии сборки...
Сразу просятся специальные:
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))) //S_64|
//S_32| lo := runtime_memhash(unsafe.Pointer(&buf[0]), uintptr(seed), uintptr(len))
//S_32| hi := runtime_memhash(unsafe.Pointer(&buf[0]), uintptr(seed>>32), uintptr(len))
//S_32| return uint64(hi)<<32 | uint64(lo)
}
|
Хоть маленечко смысла в гуглопомойке!
Появился DebRel -- стало меньше зубовного скрежета. То, что в C/C++ занимает секунды, теперь стало доступно для всех:
assert() в важном месте? Напишите //D5| Аssert(...)!
//D8| Dump(...).
R0/R1.
S_HIT.
//~D5:
~DN и ~RN включены, когда выключены DN и RN. И наоборот.
D5". Например:
| 1 |
pn, ok := my.wr.Get(kpn) //D5| lib.Assert(ok) |
| 2 |
pn, ok := my.wr.Get(kpn)
//D5| lib.Assert(ok)
_ = ok //~D5|
|
Здесь мы с помощью //~D5 предотвратили ошибку "declared and not used: ok", т.к. ее использует только Assert(). Еще пример:
| 1 |
//R0| bm := maps.NewBytesMap(0) //R1| bm := maps.NewBytesMap(N) |
| 2 |
bm := maps.NewBytesMap(0) //~R1| //R1| bm := maps.NewBytesMap(N) |
Как можно видеть, конфигурация D5 выключает оба определения bm, и мы получаем "undefined: bm". Но //~R1| спасает ситуацию...
Жить стало лучше, жить стало веселее!
Да-да, я тоже знаю, что не было их на Луне. Только эта подверсия и правда гигантский скачок:
DebRel v1.1.1 (2025-10-20), Debug/Release comment converter, freeware Copyright (c) Sergey P. Derevyago Usage: debrel [-c#] A file D0-5-10 [R5-20-30 D9-50-100 ~D9-101-105 ...] debrel [-c#] R0|D5 file1 [file2 file3 ...] debrel [-c#] C|U file1 [file2 file3 ...] debrel /* ... */ -r path mask debrel /* ... */ -f files.txt |
Мы существенно скрасили Жизнь всем категориям граждан:
debrel D5 -r . *.go и все получили по... Да, есть варианты!
Ну а самый надежный и точный -- второй. Щепотка усилий, и вы полностью контролируете ситуацию.
Но бывает, что хочется Чуда...
Да, такое мы можем. Вам теперь и под Windows дозволено задавать маски в именах директорий: examples\*\*.go вместо file1 [file2 file3]. Ну разве не песня?
И какая сейчас Суперсила? Зело цели спецназначения!
Это цели с большой буквы S и длиною не более 32 символов. Допускаются буквы и цифры, также символ подчеркивания. Все как положено:
DebRel v1.2 (2025-12-10), Debug/Release comment converter, freeware Copyright (c) Sergey P. Derevyago Usage: debrel [-c#] -A -D0-5-10 [-~R5-20-30 ...] file debrel [-c#] -D5|-R0 [-Spec1 ...] file1 [file2 ...] debrel [-c#] -C|-U file1 [file2 ...] debrel /* ... */ -r path mask debrel /* ... */ -f files.txt |
Может сразу не видно, но они дополнительные! Без Debug и Release не укажешь.
Никакая часть данного материала не может быть использована в коммерческих целях без письменного разрешения автора.