Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.86/21: Рейтинг темы: голосов - 21, средняя оценка - 4.86
45 / 21 / 6
Регистрация: 28.02.2013
Сообщений: 194

#define and debug_mode

04.02.2016, 10:51. Показов 4553. Ответов 45
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Столкнулся с необходимостью использовать при отладке довольно внушительные куски кода.
(ранее решил проблему с мелкими кусками)(смотри код)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Закомментируйте чтоб отключить debug mode
//#define DEBUG_MODE
 
#define DIR_TO_LOG "C:\\some_module_log"
 
#ifdef DEBUG_MODE
    #define CLEAR_LOG_DIR {std::system("del /q "DIR_TO_LOG);}
    #define LogToFile(filename, log) {ofstream file(std::string(DIR_TO_LOG) + filename, ios::app); file << log << std::endl; file.close();}
    #define Log(log) {ofstream file(DIR_TO_LOG"log.txt", ios::app); file << log << std::endl; file.close();}
 
#else
    #define CLEAR_LOG_DIR
    #define LogToFile(filename, log)
    #define Log(log)
    
#endif
Такой подход хорошо работал для вывода мелкой отладочной информации, и по файлам легко можно было в блокноте проследить логику выполнения кода и её (логики) соответствие задуманной.

Но теперь мне исключительно для отладки понадобилось исполнять циклы, делать вычисления и прочее
И пришла в голову гениальная идея

C++
1
2
#define StartDebugBlock /*
#define EndDebugBlock */
Но увы эта простая и элегантная идея разбилась о реальность

Или может есть какой нибудь лайфхак в этом стиле?

Добавлено через 24 минуты
Много всего перепробовал. Ответ нашелся. И всё оказалось очень просто
прямо в *.cpp файле
C++
1
2
3
4
#ifdef DEBUG_MODE
SomeBigCODE();
Another_one;
#endif
Добавлено через 2 минуты
Ну и конечно ещё раз спасибо автору статьи.
https://www.cyberforum.ru/blogs/18334/blog100.html
Перечитав которую ещё раз - понял это простое и правильное решение.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
04.02.2016, 10:51
Ответы с готовыми решениями:

#define
#define зачем нужна это заголовочный файл какие у него функции и как им ползоватса?

c++11 и $define
Есть код который прекрасно компилируется без -std=c++11, но как только я включаю эту опцию то константы препроцессора не заменяются и...

C++define
Люди добрые , помогите советом ! Фрагмент с кодом самого метода : #include &lt;iostream&gt; // для std :: cout #include...

45
 Аватар для Nosey
1379 / 406 / 144
Регистрация: 22.10.2014
Сообщений: 872
04.02.2016, 11:07
Цитата Сообщение от nefton Посмотреть сообщение
#ifdef DEBUG_MODE
Лучше замените на
C++
1
#ifndef NDEBUG
Это будет постандартней.
0
45 / 21 / 6
Регистрация: 28.02.2013
Сообщений: 194
04.02.2016, 11:24  [ТС]
Nosey, Никак нет. Это очень плохая идея.
NDEBUG определяет компилятор (это уже плохо, так как тут я уже теряю часть власти над программой)
но самое страшное - что он делает это для ВСЕЙ программы. Это недопустимо.
У меня программа состоит из десятка(ов) различных модулей.
И в каждом есть свои дебаг код.
И если я пытаюсь отладить один модуль - то мне (подобрать слово) не надо отладочные действия во всех остальных модулях. (К примеру за 1 цикл исследуемого модуля по логике программы другой модуль (давно отлаженный) срабатывает 100500 раз. И что мне будет выводится 100500 сообщений кудато?)
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
04.02.2016, 19:05
Цитата Сообщение от nefton Посмотреть сообщение
Или может есть какой нибудь лайфхак в этом стиле?
хотите что то типа такого?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <tools/log>
 
void second()
{
    dLOGGING_THIS_FUNCTION;
    dLOG [INFO] << trololo;
}
 
void first()
{
    dLOGGING_THIS_FUNCTION;
 
    dLOG [INFO] << ololo1;
    second();
 
    dLOG [INFO] << ololo2;
}
 
int main()
{
    dLOGGING_THIS_FUNCTION;
    first();
 
    dLOG [INFO] << "the end";
}
Code
1
2
3
4
5
6
7
void main()
    void first()
        [04.02.2016][19:00][iNFO] ololo1
        void second()
            [04.02.2016][19:00][iNFO] trololo
        [04.02.2016][19:00][iNFO] ololo2
    [04.02.2016][19:00][iNFO] the end
умеет многопоточность,
пасти трасу функций,

полностью выпиливаться из компиляции
(макросы схлопываются)

локально настраиваться на каждом урове стека.

настраивать стратегию логгирования.
например, если стек начал раскручиваться в обратную сторону,
и все хорошо, тогда лог можно похерить
(нафига нам информация о том, что все хорошо?
вот если пофиксил варнинг,
или ошибку - вот тогда он весь лог будет сливать на диск)

и тд, и тп.
0
45 / 21 / 6
Регистрация: 28.02.2013
Сообщений: 194
04.02.2016, 19:29  [ТС]
hoggy, непойму пост.
Например
Цитата Сообщение от hoggy Посмотреть сообщение
полностью выпиливаться из компиляции
(макросы схлопываются)
никак не совместимо с
Цитата Сообщение от hoggy Посмотреть сообщение
например, если стек начал раскручиваться в обратную сторону,
и все хорошо, тогда лог можно похерить
(нафига нам информация о том, что все хорошо?
вот если пофиксил варнинг,
или ошибку - вот тогда он весь лог будет сливать на диск)
Если это вопрос ко мне как я хочу - то ответ прост. так как сейчас есть.

файлы :
module1_debug.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Закомментируйте чтоб отключить debug mode
//#define DEBUG_MODE
 
#define DIR_TO_LOG "C:\\some_module_log"
 
#ifdef DEBUG_MODE
    #define CLEAR_LOG_DIR {std::system("del /q "DIR_TO_LOG);}
    #define LogToFile(filename, log) {ofstream file(std::string(DIR_TO_LOG) + filename, ios::app); file << log << std::endl; file.close();}
    #define Log(log) {ofstream file(DIR_TO_LOG"module1_log.txt", ios::app); file << log << std::endl; file.close();}
 
#else
    #define CLEAR_LOG_DIR
    #define LogToFile(filename, log)
    #define Log(log)
    
#endif
module2_debug.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Закомментируйте чтоб отключить debug mode
//#define DEBUG_MODE
 
#define DIR_TO_LOG "C:\\some_module_log"
 
#ifdef DEBUG_MODE
    #define CLEAR_LOG_DIR {std::system("del /q "DIR_TO_LOG);}
    #define LogToFile(filename, log) {ofstream file(std::string(DIR_TO_LOG) + filename, ios::app); file << log << std::endl; file.close();}
    #define Log(log) {ofstream file(DIR_TO_LOG"log.txt", ios::app); file << log << std::endl; file.close();}
 
#else
    #define CLEAR_LOG_DIR
    #define LogToFile(filename, log)
    #define Log(log)
    
#endif
module1.cpp
C++
1
2
3
4
5
6
include "module1_debug.h"
void SomeFunktion(){
 
   Log("some my debug"<<rand()%10);
 
}
module2.cpp
C++
1
2
3
4
5
6
include "module2_debug.h"
void SomeFunktion(){
 
   Log("some my debug 2"<<rand()%10);
 
}
ну и да, ещё пример с уровнем логов из реальной жизни
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//Закомментируйте чтоб отключить debug mode
//#define DEBUG_MODE
 
//Уровни логов
#define LOG_ALL     0
#define LOG_MIDDLE  1
#define LOG_MAIN    2
#define LOG_NONE    3
 
//Уровень логов для этого модуля
#define LOG_LEVEL LOG_MIDDLE
//Файл для логов. Закомментируйте чтоб отключить вывод в файл
//#define FILE_TO_LOG "C:/my_log.txt"
 
#ifndef FILE_TO_LOG
#define CLEAR_LOG_FILE
#ifdef DEBUG_MODE
#define Log(log,level) {if (level >= LOG_LEVEL) std::cout << log << std::endl;}
#else
#define Log(log,level) ;
#endif
#else
#define CLEAR_LOG_FILE {ofstream file(FILE_TO_LOG); file.close();}
#ifdef DEBUG_MODE
#define Log(log,level) {ofstream file(FILE_TO_LOG, ios::app); if (level >= LOG_LEVEL) file << log << endl; file.close();}
#else
#define Log(log,level) ;
#endif
#endif
 
//Определение ошибки
#define Error(error) {std::cout<<"\n\nFSM Error: "<<error<<"\n\n";system("pause");exit(0);}
Тоесть логирование включается и отключается отдельно для каждого модуля, так же в каждом модуле используется своё логирование. Гдето мне надо уровни логов, гдето не надо.
Гдето мне хватает одного файла логов, или вывода на экран,
а гдето у к примеру моделируется турнир покерный на 100 игроков и 10 столов. и мне надо логи для турнира, столов, игроков и у каждого должен быть свой файл логов.
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
04.02.2016, 21:32
Цитата Сообщение от nefton Посмотреть сообщение
никак не совместимо
макросы используются для выпиливания кода из компиляции.

пример:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// раскомментируйте этот дефайн,
// что бы активировать отладочный вывод
// #define OUT_DEBUG
 
 
 
#ifdef OUT_DEBUG
    #include <iostream>
    #define outDebug(message) message, void()
#else
    #define outDebug(message) void()
#endif
 
 
 
int main()
{
    // если отключить макрос,
    // то весь код в скобочках будет выброшен из компиляции
    outDebug( std::cout <<"hello\n" );
}
Цитата Сообщение от nefton Посмотреть сообщение
Тоесть логирование включается и отключается отдельно для каждого модуля
на мой взгляд - это неудачная идея сделает механизм практически бесполезным.

ну если вам так хочется - дерзайте.
только тогда не понятно, зачем была создана эта тема.


по хорошему, лог должен работать с "фреймами" :
уметь быть активным на определенном участке кода.

фреймы могут быть вложенными друг в друга, либо повторяться.
на каждом уровне вложенности лог должен уметь поднастраиваться,
но при этом локальные настройки не должны влиять на настройки родительских фреймов.

в этом случае становится возможным контролировать трассу вызовов функций,
реализовывать стратегии поведения для циклов.

и вообще как угодно кастомизировать и детализировать лог.
Цитата Сообщение от nefton Посмотреть сообщение
#define StartDebugBlock /*
#define EndDebugBlock */
Но увы эта простая и элегантная идея разбилась о реальность
в самом начале сообщения есть пример кода.
который как раз делает примерно то,
что вы хотите.
0
45 / 21 / 6
Регистрация: 28.02.2013
Сообщений: 194
04.02.2016, 22:43  [ТС]
Цитата Сообщение от hoggy Посмотреть сообщение
на мой взгляд - это неудачная идея сделает механизм практически бесполезным.
знать путь и пройти его не одно и тоже.
Этот механизм родился потому что по другому не получалось.
Отладочная информация - это не прихоть, потому что типа это круто и похоже на нормальный код.
И типа круто когда всё подстраивается и выводит красиво.
Это необходимость, без которой проект просто останавливается.
Это в хело ворде можно дебагером ловить ошибки логики.
Пока проект меньше 3000 строк (во всех файлах) дебагера хватало.
А когда модули проекта используются в других смежных проектах...

Цитата Сообщение от hoggy Посмотреть сообщение
по хорошему, лог должен работать с "фреймами" :
уметь быть активным на определенном участке кода.
фреймы могут быть вложенными друг в друга, либо повторяться.
на каждом уровне вложенности лог должен уметь поднастраиваться,
но при этом локальные настройки не должны влиять на настройки родительских фреймов.
в этом случае становится возможным контролировать трассу вызовов функций,
реализовывать стратегии поведения для циклов.
и вообще как угодно кастомизировать и детализировать лог.
Звучит как в сказке (правда я ничего не понял из этого).
Буду благодарен за конкретный пример.

Приведённый пример выглядит немного нелепо.
Особенно void() через запятую.
http://iproc.ru/programming/cpp-comma-operator/
Кликните здесь для просмотра всего текста
Опе*ра*ция за*пя*тая пред*на*зна*че*на для то*го, что*бы впи*хи*вать дей*ствия с по*боч*ны*ми эф*фек*та*ми в те ме*ста про*грам*мы, где ком*пи*ля*тор ожи*да*ет один опе*ра*тор. Как вы уви*ди*те да*лее, от этой воз*мож*но*сти язы*ка про*грам*ми*ро*ва*ния нет ни*ка*кой поль*зы — по*нят*ность про*грам*мы сни*жа*ет*ся, а до*пол*ни*тель*ные дей*ствия мож*но вы*пол*нить и без за*пя*тых.


Цитата Сообщение от hoggy Посмотреть сообщение
только тогда не понятно, зачем была создана эта тема.
Тема была создана потому что решение
C++
1
2
3
4
5
6
#ifdef OUT_DEBUG
    #include <iostream>
    #define outDebug(message) cout<<message<<endl;
#else
    #define outDebug(message) 
#endif
не работает для многострочного кода.

так же спустя 20 мин было найдено решение (в первом посте в конце)
0
Эксперт С++
4986 / 3093 / 456
Регистрация: 10.11.2010
Сообщений: 11,170
Записей в блоге: 10
04.02.2016, 22:45
Цитата Сообщение от nefton Посмотреть сообщение
Тема была создана потому что решение
Сами себе создали проблему и сами же её решили. Бывает...
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
04.02.2016, 23:07
Цитата Сообщение от nefton Посмотреть сообщение
Отладочная информация - это не прихоть,
дальше не интересно.
не первый день замужем.

Цитата Сообщение от nefton Посмотреть сообщение
Буду благодарен за конкретный пример.
так я ж выше вам показал дизайн использования.
если не понятно, то можно разобрать поподробнее.

Цитата Сообщение от nefton Посмотреть сообщение
Приведённый пример выглядит немного нелепо.
все, что в скобочках макроса,
выпиливается из компиляции при необходимости.
можно писать многострочный код.
что именно вас смущает?

Цитата Сообщение от nefton Посмотреть сообщение
Особенно void() через запятую.
это - моё собственное "ноу-хау"

позволяет написать такой код:
C++
1
2
if(expression)
    dOutDebug (  std::cout <<"[DEBUG] detected recursive open child..."  );
суть использования макроса - что бы можно было выпилить весь код под макросом.
схлопнувшись, макрос должен превратиться в пустоту.

но тогда, при отключении дефайна,
такой код бы поломался:

C++
1
2
3
// такое не будет правильно работать
if(expression)
   /* пустота */
и пришлось бы писать вот так:
C++
1
2
3
if(expression){ 
    dOutDebug (  std::cout <<"[DEBUG] detected recursive open child..."  ); 
}
оператор запятая в купе с void()
позволяют избежать требования использовать фигурные скобочки.

Добавлено через 57 секунд
Цитата Сообщение от Nosey Посмотреть сообщение
Это будет постандартней.
не будет. это - фича мелкомягких.
0
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
04.02.2016, 23:20
Цитата Сообщение от hoggy Посмотреть сообщение
это - фича мелкомягких.
Вообще-то нет.
Стандарт С:
Цитата Сообщение от 7.2/1
The header <assert.h> defines the assert macro and refers to another macro,
NDEBUG which is not defined by <assert.h>. If NDEBUG is defined as a macro
name at the point in the source file where <assert.h> is included, the assert
macro is defined simply as
#define assert(ignore) ((void)0)
The assert macro is redefined according to the current state of NDEBUG each
time that <assert.h> is included.
4
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
04.02.2016, 23:38
Цитата Сообщение от DrOffset Посмотреть сообщение
Вообще-то нет.
я имею ввиду, что высокоцивилизованная студия
автоматом прописывает минимум две конфигурации:
дебаг и релиз.

чего не скажешь о невиндузятных сборках.
там что пропишут, в каком нибудь мейкфайле,
то и будет.

само по себе деление на "дебаг" и "релиз" - штука условная.
целиком и полностью зависит от фантазий программистов.
часто в сборках фигурирует макрос DEBUG,
и нет никаких гарантий,
что там будет фигурировать NDEBUG

пример:

мой воркспейс в качестве базиса использует вот такие ключики:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
if(${CMAKE_GENERATOR} MATCHES "Unix Makefiles" OR ${CMAKE_GENERATOR} MATCHES "MinGW Makefiles")
 
    set(CMAKE_MAKE_PROGRAM      "${CMAKE_MAKE_PROGRAM}      -j{PROCESSOR_COUNT}"     )
    set(CMAKE_CXX_FLAGS         "${CMAKE_CXX_FLAGS}         -std=c++1y -fopenmp"     )
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++1y -fopenmp -O3" )
    set(CMAKE_CXX_FLAGS_DEBUG   "${CMAKE_CXX_FLAGS_DEBUG}   -std=c++1y -fopenmp -O0 -g3 -pedantic -Wall -Weffc++ -Wextra -Woverloaded-virtual -Wctor-dtor-privacy -Wnon-virtual-dtor -Wold-style-cast -Wconversion -Wsign-conversion -Winit-self -Wunreachable-code")
 
#    set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -std=c++1y -fopenmp -O3" )
#    set(CMAKE_CXX_FLAGS_MINSIZEREL     "${CMAKE_CXX_FLAGS_RELEASE} -std=c++1y -fopenmp -O3" )
 
elseif(MSVC)
 
    foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}       )
        string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG         )
        if(CMAKE_CXX_FLAGS_${OUTPUTCONFIG} MATCHES "/W[0-4]" )
            string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS_${OUTPUTCONFIG} ${CMAKE_CXX_FLAGS_${OUTPUTCONFIG}})
        else()
            set(CMAKE_CXX_FLAGS_${OUTPUTCONFIG} "${CMAKE_CXX_FLAGS_${OUTPUTCONFIG}} /W4")
        endif()
 
        set(CMAKE_CXX_FLAGS_${OUTPUTCONFIG} "${CMAKE_CXX_FLAGS_${OUTPUTCONFIG}} /MP /openmp")
    endforeach()
endif()
 
set(CMAKE_CXX_FLAGS_RELEASE        "${CMAKE_CXX_FLAGS_RELEASE}        -DNDEBUG" )
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DDDEBUG" )
set(CMAKE_CXX_FLAGS_MINSIZEREL     "${CMAKE_CXX_FLAGS_MINSIZEREL}     -DNDEBUG" )
set(CMAKE_CXX_FLAGS_DEBUG          "${CMAKE_CXX_FLAGS_DEBUG}          -DDEBUG"  )
фокус в том, что это - моя собственная инициатива.
без этих строк, в сборку под какие нибудь линуксы,
никто за меня бы NDEBUG бы не добавил.
0
04.02.2016, 23:39

Не по теме:

Цитата Сообщение от hoggy Посмотреть сообщение
никто за меня бы NDEBUG бы не добавил.
Это да.

0
45 / 21 / 6
Регистрация: 28.02.2013
Сообщений: 194
05.02.2016, 00:04  [ТС]
Цитата Сообщение от hoggy Посмотреть сообщение
2
if(expression)
dOutDebug ( std::cout <<"[DEBUG] detected recursive open child..." );
схлопнется в точку с запятой и никаких проблем кроме варнинга
ну или просто оставить этот void() для no_debug_mode, и убрать его с запятой из дебага

Добавлено через 5 минут
Цитата Сообщение от hoggy Посмотреть сообщение
все, что в скобочках макроса,
выпиливается из компиляции при необходимости.
можно писать многострочный код.
что именно вас смущает?
C++
1
2
3
4
dOutDebug ( 
    for (int i=0; i<param; i++)
        std::cout <<"Param["<<i<<"] = " << Param[i]<< " | ";
 );
Не прокатит.
А если там 15 строчек? писать в 1 строчку в {}?
и кто это читать потом будет?
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
05.02.2016, 00:31
Цитата Сообщение от nefton Посмотреть сообщение
никаких проблем кроме варнинга
путь варнинга - плохой путь.

Цитата Сообщение от nefton Посмотреть сообщение
просто оставить этот void() для no_debug_mode
так и есть.

благодаря void, можно вот так написать, например:

C++
1
2
3
4
if(expression)
    foo(),
    dOutDebug (  std::cout <<"[DEBUG] detected recursive open child..."  ),
    baz();
когда макрос схлопнется, получится:

C++
1
2
3
4
if(expression)
    foo(),
    void(),
    baz();
а без void, получилось бы:

C++
1
2
3
if(expression)
    foo(), ,
    baz();
что привело бы к ошибке компиляции.

Добавлено через 21 минуту
Цитата Сообщение от nefton Посмотреть сообщение
Не прокатит.
А если там 15 строчек? писать в 1 строчку в {}?
и кто это читать потом будет?
пишите нормально, и будет все ок.

вы ж не пытаетесь под assert запихать 15 строчек фигни?

код под макросом - опционален.
он в любом случае не должен перемешиваться с основным кодом,
и замыливать глаза.

поэтому, по хорошему, его следует выносить в отдельные функции.
исключения составляют только короткие конструкции,
которые можно оформить в одну две строки.

плохой код:

C++
1
2
3
4
5
6
7
8
9
10
void foo(const param& p)
{
     auto result = work(p);
 
    #ifdef DEBUG
    /* здесь километр отладочных проверок */ 
    #endif
 
    proccess(result);
}
хороший код:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
#ifdef DEBUG
bool check(const auto& result)
{
    // все необходимые проверки
}
#endif
 
void foo(const param& p)
{
     auto result = work(p);
     assert( check(result) );
     proccess(result);
}
0
45 / 21 / 6
Регистрация: 28.02.2013
Сообщений: 194
05.02.2016, 01:05  [ТС]
в последнем посте поменять местами хорошо и плохо - и всё ок.
1. Дебаг - это не только ассерт. Мало того, как рас для ассерта он и не используется.
когда кудато пришли не те параметры - это очень легко уловимая ошибка.
Дебаг и логи служат для нахождения логических ошибок.
Чтоб проследить толи делает программа.
Рассмотрим подробнее плохой пример кода

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#ifdef DEBUG
bool check0(const auto& result)
{
    // все необходимые проверки
}
bool check1(const auto& result)
{
    // все необходимые проверки
}
bool check2(const auto& result)
{
    // все необходимые проверки
}
bool check3(const auto& result)
{
    // все необходимые проверки
}
#endif
 
 
//500 строк кода (в том числе использующий эти чеки ЕДИНОЖДЫ!!!!)
 
//Наша функция делает тото и тото (это комментарий)
void foo(const param& p)
{
     //Для начала сделаем первую часть работы
     auto result = work(p);
    //Проверим чтото
     assert( check2(result) );
     ///А что мы проверили? ну так просто надо пролистать 3 страницы вверх и посмотреть
     //Ну да, запомнив при этом где мы были, так как впереди ещё 3 страницы
 
     //А тут мы выведем лог в файл чтоб проследить всё ли посчитано как надо
     Log(check4()); //И в том же стиле посмотрим в оглавление, или вообще в другой файл
     //На функцию которая связанно непосредственно с "первой частью работы" (если вы не забыли это 5 строчек выше)
 
    //Вторая часть работы
     proccess(result);
}
 
//Ешё 200 строк кода
Добавлено через 7 минут
Забегая вперед и предупреждая холивар. Прокомментирую свои слова про не используется для ассерта.
Я имею в виду что более 95% отладочного кода - это вывод в удобочитаемой форме того, что делает программа.
И лишь 5% это проверки (большинство из которых не надо, так как просто приведёт к крашу программы).
А починить программу которая неработает в 100500 раз легче чем починить программу которая работает, но возможно как то не так.
И эта отладочная информация ВСЕГДА НЕПОСРЕДСТВЕННО связана с предыдушим кодом.
И выносить её в другой файл или начало файла - просто преступление против здравого смысла.
0
45 / 21 / 6
Регистрация: 28.02.2013
Сообщений: 194
05.02.2016, 01:13  [ТС]
Ну и да, в хорошем коде не забываем отступы - и всё ок.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void foo(const param& p)
{
     auto result = work(p);
 
    #ifdef DEBUG
         //здесь километр отладочных проверок
         PerviyMetrKilometra();
         Vtoroy();
         for (int metr = 3; metr < 1000; metr++){
              NMetrKilometra(metr);
              i_eshe_nemnogo = 56 - qwerty;
         }
         IPodPomidory(100500); 
    #endif
 
    proccess(result);
}
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
05.02.2016, 01:35
Цитата Сообщение от nefton Посмотреть сообщение
//Проверим чтото
* * *assert( check2(result) );
* * *///А что мы проверили? ну так просто надо пролистать 3 страницы вверх и посмотреть
* * *//Ну да, запомнив при этом где мы были, так как впереди ещё 3 страницы
вам не нужно знать, что именно там проверяется.

не нужно ничего пролистывать.
проверка - второстепенная, опциональная деталь.

в хорошем коде, программист вообще может не вникать в детали её работы.

технически, можно вообще удалить весь ассерт-код,
и это никак не должно влиять на бизнес-логику самой функции.

собственно в этом и суть:
хорошо читаемый код красноречиво отображает свою суть,
не замусориваясь всякими не относящимися к этой сути второстепенными деталями.


если что нибудь пойдет через жёппь,
только тогда станет интересно,
что произошло в проверочном коде.

опять таки, хороший код услужливо подскажет суть проблемы.
простым английским текстом,
он сообщит программисту суть диагностики.
не напрягая программиста необходимостью вникать во все детали.
но если все таки придется - проверка инкапсулированна
в отдельной функции.
и понять её при необходимости будет не сложно.


это называется "разделяй и властвуй" - фундаментальное свойство ООП,
официально именуемое "инкапсуляцией".

в противовес можно представить себе монолитную портянку "непойми чего".
суть которой давно растворилась в гороховом супе не относящихся к ней деталей.

Добавлено через 7 минут
Цитата Сообщение от nefton Посмотреть сообщение
Ну и да, в хорошем коде не забываем отступы - и всё ок.
void foo(const param& p)
{
* * *auto result = work(p);
#ifdef DEBUG
* * * * *//здесь километр отладочных проверок
* * * * *PerviyMetrKilometra();
* * * * *Vtoroy();
* * * * *for (int metr = 3; metr < 1000; metr++){
* * * * * * * NMetrKilometra(metr);
* * * * * * * i_eshe_nemnogo = 56 - qwerty;
* * * * *}
* * * * *IPodPomidory(100500);
* * #endif
proccess(result);
}
суть этой функции - всего в двух строчках:
C++
1
2
auto result = work(p);
proccess(result);
а не в километре проверок,
в которых эти две функции просто утонут.
программист, который читает код,
рискует забыть с чего все началось,
и зачем вообще затевалось.
потому что 99% времени по вашему рецепту он будет читать
не относящиеся к сути подробности проверок.
0
45 / 21 / 6
Регистрация: 28.02.2013
Сообщений: 194
05.02.2016, 08:30  [ТС]
Вы невнимательно читали мой последний пост.
мне не нужны ни ассерты ни проверки.
Мне нужно логирование человеческим языком что делает программа.
Без этого невозможно создать в разумные сроки чтонибудь действительно большое и сложное.
Програма крашится, или просто выдаёт подозрительный результат - включаешь логи, запускаешь прогу и потом смотришь по созданным файлам что, когда и почему пошло не так.
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
05.02.2016, 22:10
Цитата Сообщение от nefton Посмотреть сообщение
Вы невнимательно читали мой последний пост.
я не просто внимательно прочитал ваш пост,
я ещё и понял прекрасно вашу точку зрения.
потому что и сам проходил через нечто подобное
несколько лет назад.

сейчас вам нужен
C++
1
2
3
#ifdef TROLOLO
// многострочная заморочка с логом
#endif
что бы иметь возможность написать много опциональных буковок,
которые не являются частью бизнес-логики функции.

когда нибудь вы поймете,
что это плохой путь - захламлять бизнес-логику всяким барахлом,
которое напрямую не имеет к ней отношение.

и если вынести все эти буковки в отдельную функцию,
это сразу все упростит:
улучшит читабельность.
и для лога вам достаточно будет простенького макроса,
аля assert.
0
45 / 21 / 6
Регистрация: 28.02.2013
Сообщений: 194
05.02.2016, 23:30  [ТС]
Это не опциональные буковки.
Последние 3 дня я бился над проблемой, что код выдавал странные (неверные) результаты.
Чтоб узнать сам факт их неверности (описка в расчётах оказалось) требуется ночь работы программы!!!!!!
Тоесть 1 число считается целую ночь!!! И только так можно с какойто вероятностью судить о странных результатах.
Просмотр 10ти страниц (в разных файлах естественно) кода отвечающего за этот конкретный расчёт - не дал результатов.
И только подробное логирование человеческим языком помогло найти ошибку (к тому же не одну)
и увидеть то место где я накосячил.
Это факт. Подробное логирование = проблема была решена.
И это далеко не первый раз.
Ну и да, дебагер естественно абсолютно бессилен, так как он оперирует числами, а проблема нашлась только когда все данные были представлены в своём человеческом виде.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
05.02.2016, 23:30
Помогаю со студенческими работами здесь

#define
Здравствуйте, дорогие программисты! сразу хочу сказать, что в С++ я совсем недавно, поэтому толком ничего не знаю Во-первых,...

define
И еще такой вопрос для чего служит #define ??

#define c ::
Подскажите как реализовать такую замену: #define sa2::sys::getClientKernel()-&gt;getXDBTManager() cls_SimpleXDBTManager::Instance() ...

define не
Здравствуйте. &quot;Дефайню&quot; &quot;%f&quot; для вывода: #define fss &quot;%f&quot;; . И потом делаю вывод вот такой вот: for(i=0;i&lt;n;i++)...

define
Всем здрасьте , что означает эта строчка? #define MAX(a,b) a&gt;b? a:b


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка. Рецензия / Мнение Это мой обзор планшета X220 с точки зрения школьника. Недавно я решила попытаться уменьшить свой. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru