Инструмент программирования на C для замены переменных значениями в исходном коде

Я часто отлаживаю числовые подпрограммы на C. Это означает, что я запускаю программу с помощью gdb и перехожу к функции, которую нужно отладить. Затем я сравниваю числовые значения с моими ожиданиями, распечатывая переменные с помощью gdb. Очевидно, эта процедура утомительна для более длительных процедур. В частности, мне нужно запоминать значения различных переменных между последующими запусками, если я изменяю процедуру и хочу сравнить с предыдущими результатами. В некоторых случаях очень помогло бы (особенно, если подпрограмма более или менее линейна), если бы у меня был инструмент, который автоматически заменяет переменные их числовыми значениями, встречающимися во время выполнения. Например. короткий (тривиальный) пример процедуры

myfunc(double a, double b)
{
  double tmp_a, tmp_b, c;

  tmp_a = a*a;
  tmp_b = b*b;

  c = sqrt(tmp_a+tmp_b);

  return c;
}

может быть преобразован в

myfunc(double a<1.0>, double b<2.0>)
{
  double tmp_a, tmp_b, c;

  tmp_a = a<1.0>*a<1.0>;
  tmp_b = b<2.0>*b<2.0>;

  c = sqrt(tmp_a<1.0>+tmp_b<4.0>);

  return c<2.236067977499789696e+00>;
}

Я мог легко сравнить результаты последующих запусков с помощью инструмента сравнения. Также я мог сравнивать промежуточные численные результаты с результатами произвольной точности, вставляя результат в систему компьютерной алгебры. Приблизительная идея состоит в том, что драйвер gdb выполняет двоичный файл до указанной процедуры, выполняет ее шаг за шагом (каждый раз заменяя все переменные в шаге их соответствующими значениями в это время) и, наконец, завершает работу. Подсказки к существующему программному обеспечению или идеи для реализации приветствуются. Возможно, есть решение, основанное на perl, использующее существующие интерфейсы gdb, такие как Devel::GDB (не уверен, что этот достаточно взрослый).


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


person highsciguy    schedule 20.02.2013    source источник
comment
Это не замена, это какая-то маркировка. Я не знаю инструмента для этого, но было бы разумнее использовать комментарии, то есть a/*1.0*/, поскольку это, по крайней мере, позволило бы создать исходный код.   -  person unwind    schedule 20.02.2013
comment
Что ж, в идеальном случае это можно было бы свободно настраивать. Так что у меня тоже могла бы быть настоящая замена (это упростило бы копирование в систему компьютерной алгебры, которая поддерживает синтаксис C).   -  person highsciguy    schedule 20.02.2013


Ответы (2)


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

На рынке есть продукты, которые выполняют «анализ потока кода» и понимают граничные условия, «это ошибка, если sqrt вызывается с отрицательным значением» и тому подобное. Coverity - это инструмент (далеко не бесплатный), который делает это на C / C ++ и выплевывает: «Вы пытаетесь сделать здесь что-то глупое, вы уверены, что это правильно?» введите сообщения для вашего кода.

Valgrind также может делать похожие вещи.

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

person Mats Petersson    schedule 20.02.2013
comment
Как я уже сказал, приведенный выше пример тривиален. Оптимизация компилятора, подобная упомянутой вами, будет отключена с помощью -O0. Обратите внимание, что я в первую очередь НЕ говорю об ошибке типа sqrt (-1) (я бы искал их, используя расширение исключений с плавающей запятой gnu) или других ошибках, которые отладчик может обнаружить автоматически. В основном меня интересуют ошибки конечной точности, которые не обязательно приводят к неправильным операциям. Ошибки этого типа, которые появляются после сотен итераций, все равно будет труднее обнаружить, если я буду отлаживать пошагово. - person highsciguy; 20.02.2013
comment
И в журнале из 10000 строк вывода тоже было бы довольно сложно обнаружить. И я ожидаю, что в коде есть только определенные места, которые особенно чувствительны, поэтому добавление ручного ведения журнала может быть лучшим выбором. - person Mats Petersson; 20.02.2013
comment
Я говорю о процедурах, длина которых составляет порядка 1000 строк. 10000 строк вывода - это не много ... С помощью графического инструмента сравнения, такого как kdiff3 (есть много других), я считаю, что вполне возможно что-то увидеть. - person highsciguy; 20.02.2013
comment
Да, и если у вас есть 1000 строк, которые повторяются 10 раз, вы получите 10000 строк. На 1000 итераций у вас есть миллион строк. И вы можете что-то diff только в том случае, если у вас есть шаблон с правильными результатами. Я хочу сказать, что вы получаете очень много результатов, большая часть которых, вероятно, бессмысленна для того, что вы ищете. - person Mats Petersson; 20.02.2013
comment
Я понимаю вашу точку зрения и согласен с тем, что в какой-то момент это станет невыполнимым. В конце концов, я пишу код на C, потому что он должен пройти через гораздо больше итераций, чем я когда-либо смогу выполнить. Но, конечно, уже может быть очень полезно сравнить результат одной итерации, который я мог бы легко выделить. Основная цель - сделать отдельные итерации безопасными, верно. Я уверен, что в определенных случаях (о которых я говорю) такой вывод был бы очень полезен. Вопрос только в том, как его произвести ... - person highsciguy; 20.02.2013

вы можете пойти другим путем:
Создайте файл журнала (можно сделать с помощью printf и перенаправить стандартный вывод при запуске). вы можете распечатать интересующие значения и diff два журнала из разных прогонов.

person Roee Gavirel    schedule 20.02.2013
comment
Конечно, я печатаю ключевые переменные для своего кода. Но представьте себе код, который слишком долго будет делать вручную для каждого! Таковы мои распорядки. Если бы я даже попытался сделать это для одного, я мог бы придумать первый прототип для описанного кода за меньшее время. И мне нужно было бы переделывать его после каждого изменения в коде. - person highsciguy; 20.02.2013