Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1] 2  Все   Вниз
  Печать  
Автор Тема: Управляемая компиляция  (Прочитано 41451 раз)
0 Пользователей и 13 Гостей смотрят эту тему.
ezus
Опытный

il
Offline Offline

« : 16-01-2011 09:39 » 

В инете я нашел много всего на эту тему, но всё рядом, а хотелось бы получить простой ответ: есть нужная мне возможность или нет.
Если есть, то Какая? Если нет, то может существует какой-нибудь трик?

Частная проблема:
Есть функция, которая вызывается во множестве мест. Эта фунция используется в качестве "строительных лесов" и нужна только на этапе отладки.  Она обеспечивает управляемую отладочную печать, управляемые брекпоинты и т.п.

Ранее в С++ было так.
Код:
#define FFNEED

#ifdef FFNEED
#define FF(parameters...) ff(parameters...)
#else
#define FF(parameters...)
#endif

Комментируя #define FFNEED, я отключал эту функцию во всем модуле.

Есть ли похожая возможность в C#?

Спасибо.


Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 16-01-2011 12:01 » 

ezus, http://msdn.microsoft.com/library/ed8yd1ha.aspx
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
ezus
Опытный

il
Offline Offline

« Ответ #2 : 17-01-2011 08:01 » 

Простите, но я не понял как при помощь
http://msdn.microsoft.com/library/ed8yd1ha.aspx
сделать, то что я хочу.

#define не дает возможность определить функции,
а #if #else #endif делают текст абсолютно неудобочитаемым.
 
Записан
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 17-01-2011 08:17 » 

В принципе, целые функции можно делать опционально компилируемыми с помощью атрибутов. Пример есть тут: http://msdn.microsoft.com/ru-ru/library/z0w1kczw.aspx
Более подробно - тут: http://msdn.microsoft.com/ru-ru/library/system.diagnostics.conditionalattribute.aspx
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 17-01-2011 11:28 » 

ezus, зачем же так прямолинейно? Достаточно творчески подойти к делу:
Код: (C#)
void debugFunction()
{
  #if DEBUG
  // ... нужное действие
  #endif
}

void myFunction()
{
  //... какие-то действия
  debugFunction();
  //... какие-то действия
}
И может даже комплиятор выкинет этот вызов, если работает со включенной оптимизацией.

Или, действительно, оперировать атрибутами.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
ezus
Опытный

il
Offline Offline

« Ответ #5 : 17-01-2011 12:59 » 

Код: (C#)
void debugFunction()
{
  #if DEBUG
  // ... нужное действие
  #endif
}

void myFunction()
{
  //... какие-то действия
  debugFunction();
  //... какие-то действия
}
Красиво и почти очевидно.
Но:
а) это не всегда функция
б) главные потери приходятся не на вызов, а на формирование часто очень тяжелых параметров, и именно этого хотелось бы избежать

Цитата
И может даже комплиятор выкинет этот вызов, если работает со включенной оптимизацией.
А вот это действительно ОЧЕНЬ интересно.
Может быть вы знаете какой это уровень оптимизации?
Останется только проверить будут ли считаться параметры.

Цитата
Или, действительно, оперировать атрибутами.
А здесь есть ли какие-нибудь идеи?

Спасибо.
Записан
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 17-01-2011 13:25 » 

В случае атрибутов компилятор вызов должен выкинуть совсем. И, надо полагать, рассчитываемые для него аргументы (если больше нигде не используются). Пример я выше давал - там как раз описывается, как мне кажется, нужный случай.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 17-01-2011 14:56 » 

Цитата: ezus
б) главные потери приходятся не на вызов, а на формирование часто очень тяжелых параметров, и именно этого хотелось бы избежать
Да не вопрос. Есть такая штука, как "ленивые вычисления".

Код: (C#)
    class Program
    {
        delegate object[] GetDebugParameters();

        static void debugFunction(GetDebugParameters getParameters)
        {
#if DEBUG
            object[] parameters = getParameters();
            Console.WriteLine("Debug");
            foreach (object parameter in parameters)
            {
                if (parameter.GetType().IsArray)
                {
                    Console.WriteLine("Array of {0} items.", (parameter as Array).LongLength);
                }
                else
                {
                    Console.WriteLine(parameter.ToString());
                }
            }
#endif
        }

        static void myFunction()
        {
            debugFunction(() => {
                Console.Write("Calculating parameters... ");
                const int maxI = 1000, maxJ = 1000;
                int[,] matrix = new int[maxI, maxJ];
                for(int i = 0; i < maxI; ++i)
                {
                    for(int j = 0; j < maxJ; ++j)
                    {
                        matrix[i, j] = i * j;
                    }
                    Thread.Sleep(1);
                }
                Console.WriteLine("done.");
                return new object[] { 0, "test", matrix };
            });
        }

        static void Main(string[] args)
        {
            myFunction();
            Console.WriteLine("Press any key...");
            Console.ReadKey();
        }
    }
Достаточно вычисление параметров поместить в лямбда-функцию, которую вызывает функция debugFunction - и процесс вычисления будет вызываться только тогда, когда это запросит debugFunction, который не запросит этого, если вызывающий код вырезан компилятором.

Цитата: ezus
Может быть вы знаете какой это уровень оптимизации?
Посмотрел - нет там никаких уровней. Либо есть оптимизация кода, либо нет. Что касается выкидывания расчёта параметров пустых функций, то этого не происходит.

Про атрибуты - там же по ссылкам Вада всё написано. Это гораздо проще, чем лямбда-функции.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
ezus
Опытный

il
Offline Offline

« Ответ #8 : 17-01-2011 15:53 » 

Dimka
Я уже подумал про делегаты, однако это штука, конечно, красивая, но на начальных стадиях трудно переваримая.
Что ж будем жевать.

Спасибо.

Добавлено через 6 минут и 56 секунд:
В принципе, целые функции можно делать опционально компилируемыми с помощью атрибутов. Пример есть тут: http://msdn.microsoft.com/ru-ru/library/z0w1kczw.aspx
Более подробно - тут: http://msdn.microsoft.com/ru-ru/library/system.diagnostics.conditionalattribute.aspx
Спасибо за линки.
« Последнее редактирование: 17-01-2011 15:59 от ezus » Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #9 : 17-01-2011 16:02 » 

Главное тут, конечно, не столько делегаты, сколько лямбда-функции в нужном месте в соответствующем контексте (замыкании) основной функции (т.е. имеющие доступ к локальным переменным и параметрам myFunction несмотря на то, что вызываются из debugFunction). Это позволяет кусок алгоритма выполнять только по запросу, а не всякий раз, и условия вызова держать где-то за пределами алгоритма.
« Последнее редактирование: 17-01-2011 17:27 от Dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
ezus
Опытный

il
Offline Offline

« Ответ #10 : 17-01-2011 16:26 » 

В случае атрибутов компилятор вызов должен выкинуть совсем. И, надо полагать, рассчитываемые для него аргументы (если больше нигде не используются). Пример я выше давал - там как раз описывается, как мне кажется, нужный случай.
Это почти то, что надо.
Но есть вопрос:
Я понял, что #define действует только в пределах одного файла или из стартовой строки.
А есть ли возможность собрать эти #define-ы в каком-нибудь одном файле? Или что-то подобное?
Чтобы управление этим "процессом" собрать в одном месте.

Добавлено через 4 минуты и 25 секунд:
Dimka
Спасибо за ясные разъяснения, что-то подобное я себе и подозревал.
А сейчас сомнения почти пропали.
Спасибо.

Добавлено через 15 минут и 28 секунд:
Нет, к сожалению, аттрибуты не помогают.
Они отключают все функцию, а мне надо отключать только некоторые вызовы.
« Последнее редактирование: 17-01-2011 16:46 от ezus » Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #11 : 17-01-2011 17:30 » 

Цитата: ezus
Я понял, что #define действует только в пределах одного файла или из стартовой строки.
А есть ли возможность собрать эти #define-ы в каком-нибудь одном файле? Или что-то подобное?
Чтобы управление этим "процессом" собрать в одном месте.
Непонятно. Сами определения задаются в свойствах проекта - грубо говоря, в параметрах командной строки компилятора. А проверки условий собирать в одном файле - как-то странновато.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #12 : 17-01-2011 17:33 » 

Без примера сложно представить, в чём может быть сложность. По идее, можно сделать отдельное условие для набора вызовов (и, наверное, нужно, если они по такому признаку группируются).

Глобальный define можно делать в свойствах проекта: http://msdn.microsoft.com/ru-ru/library/0feaad6z.aspx
Записан
ezus
Опытный

il
Offline Offline

« Ответ #13 : 18-01-2011 07:18 » 

Вад Спасибо, разобрался и заработало.

А проверки условий собирать в одном файле - как-то странновато.
Да, ничего особенного. Просто удобно из одного мест управлять активностью отладки по всему комплексу.

Вроде понял, разобрался и принял решения по реализации. Сейчас попробую это сделать.

Еще раз спасибо всем.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #14 : 18-01-2011 11:22 » 

Цитата: ezus
Просто удобно из одного мест управлять активностью отладки по всему комплексу.
Я этого не понимаю. В C++ есть #include, которая позволяет компилятору в каждый файл включить какие-то строчки. Но это вовсе не "одно место".
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
ezus
Опытный

il
Offline Offline

« Ответ #15 : 14-02-2011 16:01 » new

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

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

Есть сервисный класс Log, который выборочно печатает только нужные строки. Выборка многокритериальная: по модулям, по функциям, по спецкоду, начиная с номера строки и т.д. и т.п.
Параметры отладки определяются обычным текстовым файлом, который всегда загружается при старте, но может быть перезагружен в любое время.

Пример:
Программа падает фиг его знает где. Задаешь коды Beg и End и получаешь только входы и выходы - за один прогон знаешь в какой функции упала. Для второго прогона задаешь имя функции и получаешь печать во всех, заранее определенных тобой, точках.
Причем печать осмысленная, контекстнозависимая.

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

Потребность в отключении очевидна. Оператора if не достаточно, т.к. формирование самих параметров печати может требовать больших ресурсов, как времени так и памяти.

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

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

Записан
RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #16 : 14-02-2011 17:05 » 

Не обязательно - рекурсия.
https://club.shelek.ru/viewart.php?id=184
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #17 : 14-02-2011 19:21 » 

Программа падает фиг его знает где.

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

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
ezus
Опытный

il
Offline Offline

« Ответ #18 : 15-02-2011 06:59 » 

Как-то слабо могу представить себе такую ситуацию. Обычно, оказываешься в точке останова и можешь детально изучить обстановку.
1. Но иногда для понимания ситуации необходимо знать предисторию, особенно когда играешься с рекурсией.
2. Часто бывает, что само падение происходит во внутренних dll-ях системы, и тогда кроме ассемблера и 3 строчек в стеке ты ничего не видишь.
Записан
ezus
Опытный

il
Offline Offline

« Ответ #19 : 15-02-2011 07:17 » 

Не обязательно - рекурсия.
https://club.shelek.ru/viewart.php?id=184
Спасибо, очень славная статейка, правда, я не понял к чему твое замечание.
Что? Не только рекурсия приводит к подобной потребности?
Или рекурсия не обязательна?

Что она не обязательна я знаю не понаслышке. До появления аппаратного стека она во многих языках вообще была запрещена, или разрешена со множеством оговорок и ограничений, например PL/1 на IBM-360. И тогда нам приходилось выкручиваться, выдумывая различные подходы для работы с деревьями. Так что я знаю, что рекурсия не обязательна.

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

cy
Offline Offline
Пол: Мужской
Дорогие россияне


WWW
« Ответ #20 : 15-02-2011 16:06 » 

ezus, в VisualStudio ты можешь поставить брейкпойнт с условием - и он выпадет только в нужном тебе случае - "контекстозависимый", как ты сказал Улыбаюсь
Записан

Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично
RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #21 : 15-02-2011 16:42 » 

ezus, там не одна статья. Вот продолжение:
https://club.shelek.ru/viewart.php?id=205
https://club.shelek.ru/viewart.php?id=220
https://club.shelek.ru/viewart.php?id=226

Суть в том, что рекурсивный алгоритм можно заменить на итеративный и наоборот. Причем итеративный может поддаваться распараллеливанию.
« Последнее редактирование: 15-02-2011 16:44 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
ezus
Опытный

il
Offline Offline

« Ответ #22 : 15-02-2011 19:41 » 

ezus, в VisualStudio ты можешь поставить брейкпойнт с условием - и он выпадет только в нужном тебе случае - "контекстозависимый", как ты сказал Улыбаюсь
Спасибо, я знаю, но это не решает всех проблем. Надо как минимум сначала знать ГДЕ поставить.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #23 : 15-02-2011 19:49 » 

VS умеет автоматически выходит в отладчик в случае возникновения исключительной ситуации. Почему не включить перехват исключений отладчиком и не изучать ошибку в месте её генерации?
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
ezus
Опытный

il
Offline Offline

« Ответ #24 : 15-02-2011 19:55 » 

ezus, там не одна статья. Вот продолжение:
Суть в том, что рекурсивный алгоритм можно заменить на итеративный и наоборот. Причем итеративный может поддаваться распараллеливанию.
Как я уже писал и сейчас подтверждаю - очень славные статьи, для многих наверное полезные, хотя ничего нового для себя я там не нашел.

Рекурсия - полезна, часто - эффективна, бывает кратка и красива, но притом она очень опасна и трудно перевариваемая.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #25 : 15-02-2011 20:05 » 

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

ezus
Опытный

il
Offline Offline

« Ответ #26 : 15-02-2011 20:06 » 

VS умеет автоматически выходит в отладчик в случае возникновения исключительной ситуации. Почему не включить перехват исключений отладчиком и не изучать ошибку в месте её генерации?
Почему не включать, можно и включить, но я не думаю, что ты считаешь это единственным или самым эффективным методом отладки в любой ситуации.
Меня, например, одно время мучила ситуация в которой система просто зависала на системном уровне, или это казалось, что она замирает там, т.к. попытки остановить ее дебагом  указывали всегда на этот уровень. Может быть свопинг, может быть какие-то другие приколы с выделением памяти в условиях ее нехватки. Или например вывод в листбокс огромных массивов, по ошибке конечно, просто фильтры не сработали, а вывод на экран выполнялся в конце вычислений, и естесственно, я в первую очередь грешил на вычисления и  долго тыкался с брекпоинтами, пока не запустил печать в режиме вход\выход, и сразу ВСЕ стало ясно.

Добавлено через 3 минуты и 36 секунд:
Рекурсия - полезна, часто - эффективна, бывает кратка и красива, но притом она очень опасна и трудно перевариваемая.
и почти ото всех минусов очень просто избавляется введением своего стека Улыбаюсь

Прости - не понял  Здесь была моя ладья...  Не понял
От чего избовляет и что такое свой стек
Или это просто  Улыбаюсь Ага Что, съел?
« Последнее редактирование: 15-02-2011 20:10 от ezus » Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #27 : 15-02-2011 20:18 » 

ezus, избавляет от опасности stack_overflow, а также делает более наглядными итерации

а стек - любой контейнер
Записан

Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #28 : 15-02-2011 20:20 » 

ezus, свой стек - это собственная организация стека (например, на массиве), нужная для алгоритма, который рекурсию реализует в цикле, а не вызовом процедур. Этот стек гораздо удобнее изучать отладчиком, чем в стеке вызовов раскапывать локальные переменные.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
ezus
Опытный

il
Offline Offline

« Ответ #29 : 15-02-2011 20:38 » 

Спасибо Улыбаюсь
Я уже понял, что имеется в виду имитация рекурсии. Ну это можно реализовать разными способами. Я просто не люблю привносить в программу того, что на прямую не вытекает из задачи или хотя бы алгоритма. Если это рекурсия, то пусть будет чистая рекурсия, а если нет, то и мыслить я буду категориями циклов.
Записан
Страниц: [1] 2  Все   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines