Как определить, откуда печатается число в MATLAB? - PullRequest
9 голосов
/ 14 мая 2009

В MATLAB как узнать, где в коде выводится переменная?

У меня около 10 тысяч строк кода MATLAB, над которым работают около 4 человек. Где-то кто-то сбросил переменную в сценарии MATLAB обычным способом:

foo

К сожалению, я не знаю, какая переменная получает вывод. И выход загромождает другие более важные выходы.

Есть идеи?

p.s. Кто-нибудь когда-нибудь пытался перезаписать Standard.out? Так как интеграция MATLAB и Java очень тесная, сработает ли это? Уловка, которую я использовал в Java, когда столкнулся с этой проблемой, заключается в замене Standard.out моей собственной версией.

Ответы [ 9 ]

7 голосов
/ 14 мая 2009

Ох, я тоже это ненавижу. Я бы хотел, чтобы у Matlab был «dbstop if display», чтобы остановиться именно на этом.

Хорошая идея - обход минтона от Вейина. Однако Mlint не может видеть динамический код, такой как аргументы для eval () или строковые значения для обработки обратных вызовов. Я побежал, чтобы выводить как это в обратных вызовах, как это, где update_table () возвращает что-то в некоторых условиях.

uicontrol('Style','pushbutton', 'Callback','update_table')

Вы можете использовать метод "duck-punch" во встроенных типах, чтобы получить доступ к dbstop. В каталоге на вашем пути Matlab создайте новый каталог с именем "@double" и создайте файл @ double / display.m следующим образом.

function display(varargin)
builtin('display', varargin{:});

Тогда вы можете сделать

dbstop in double/display at 2

и запустите ваш код. Теперь вы попадете в отладчик, когда неявно вызывается display из пропущенной точки с запятой, в том числе из динамического кода. Делая это для @double, кажется, охватывает и char и клетки. Если отображается другой тип, возможно, вам придется поэкспериментировать.

Возможно, вы могли бы переопределить встроенную функцию disp () таким же образом. Я думаю, что это было бы аналогично пользовательской замене потока Java System.out.

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

5 голосов
/ 14 мая 2009

Это типичная схема, которую mlint поможет вам найти:

alt text

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

3 голосов
/ 15 мая 2009

Мне нравится идея "dbstop if display", однако это не та опция dbstop, о которой я знаю.

Если все остальное терпит неудачу, есть надежда. Млинт - хорошая идея, но если в ней много тысяч строк и много функций, то вы никогда не найдете преступника. Хуже того, если этот код был написан небрежно, появятся миллионы флагов mlint. Как вы его сузите?

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

ans = 
      stuff

или как

foo = 
      stuff

Тогда это было записано с дисплеем. Если это выходит просто

stuff

тогда виновник дисп. Почему это имеет значение? Перегрузить обидчика. Создайте новый каталог в некотором каталоге, который находится в верхней части пути поиска MATLAB, с именем @double (при условии, что выходные данные являются двойной переменной. Если это символ, то вам понадобится каталог @char.) НЕ ставьте символ @ Удвойте сам каталог в пути поиска MATLAB, просто поместите его в какой-то каталог, который находится на вашем пути.

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

Теперь установите точку отладки внутри новой функции. Каждый раз, когда вывод генерируется на экран, эта функция будет вызываться. Если существует несколько событий, вам может понадобиться использовать отладчик, чтобы разрешить обработку, пока нарушитель не окажется в ловушке. В конце концов, этот процесс захватит наступательную линию. Помните, вы в отладчике! Используйте отладчик, чтобы определить, какая функция называется disp и где. Вы можете выйти из дисплеев, отобразить или просто просмотреть содержимое dbstack, чтобы увидеть, что произошло.

Когда все будет сделано и проблема устранена, удалите этот дополнительный каталог и добавленную в него функцию disp / display.

3 голосов
/ 14 мая 2009

Если у вас есть строка, такая как:

foo = 2

и нет ";" в конце вывод выводится на экран с именем переменной, которое появляется первым:

foo =

     2

В этом случае вам нужно найти в файле строку «foo =» и найти строку, в которой отсутствует «;».

Если вы видите вывод без появления имени переменной, то вывод, вероятно, выводится на экран с помощью функции DISP или FPRINTF . Поиск в файле «disp» или «fprintf» должен помочь вам найти, где отображаются данные.

Если вы видите вывод с именем переменной «ans», то это тот случай, когда вычисление выполняется, не помещается в переменную, и отсутствует символ ';' в конце строки, например:

size(foo)

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

1 голос
/ 28 августа 2014

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

1) В командной строке Matlab включите «more».

more on

2) Измените размер окна prompt-y / terminal-y до простой строки текста по высоте.

3) Запустите код. Он будет останавливаться там, где это необходимо для печати, поскольку нет места для его печати (больше - блокировка при нажатии [пробел] или [вниз]).

4) Нажмите [ctrl] - [C], чтобы убить вашу программу в том месте, где она не может печатать.

5) Верните область подсказки к нормальному размеру. Начиная с верхней части трассы, нажмите на кликабельные биты в красном тексте. Это ваши потенциальные виновники. (Конечно, вам может понадобиться нажать [вниз] и т. Д., Чтобы передать части, где код фактически предназначен для печати.)

1 голос
/ 03 мая 2012

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

  1. Добавить точку останова в первой строке скрипта / функции самого высокого уровня, которая выдает нежелательный результат. Запустите функцию / скрипт.
  2. переступайте через строки (не входя), пока не увидите нежелательный вывод.
  3. Когда вы найдете строку / функцию, которая производит вывод, либо исправьте ее, если она находится в этом файле, либо откройте подфункцию / скрипт, который производит вывод. Удалите точку останова из функции более высокого уровня и поместите точку останова в первую строку функции более низкого уровня. Повторяйте с шага 1 до тех пор, пока не будет найдена линия, производящая вывод.

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

1 голос
/ 06 ноября 2009

Перегрузка Эндрю Янке - очень полезный совет Единственное, что вместо использования dbstop, я считаю, что следующее работает лучше по той простой причине, что установка остановки в display.m приведет к приостановке выполнения при каждом вызове display.m, даже если ничего не записано.

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

function display(varargin)
builtin('display', varargin{:});
if isempty(varargin{1})==0
keyboard
end
1 голос
/ 14 мая 2009

Вы можете запустить mlint как функцию и интерпретировать результаты.

>> I = mlint('filename','-struct');
>> isErrorMessage = arrayfun(@(S)strcmp(S.message,...
      'Terminate statement with semicolon to suppress output (in functions).'),I);
>>I(isErrorMessage ).line

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

Если вы хотите найти вызовы к disp () или fprintf (), вам нужно прочитать текст файла и использовать регулярные выражения для поиска вызовов.

Примечание. Если вы используете сценарий вместо функции, вам нужно изменить вышеприведенное сообщение следующим образом: «Завершить оператор точкой с запятой для подавления вывода (в сценариях).»

0 голосов
/ 14 мая 2009

Вам нужно пройти через все ваши m-файлы (возможно, с помощью рекурсивной функции или unix ('find -type f -iname * .m')). Вызовите mlint для каждого имени файла:

r = mlint(filename);

r будет (возможно, пустой) структурой с полем сообщения. Найдите сообщение, которое начинается с «Оператор Terminate с точкой с запятой для подавления вывода».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...