Есть ли способ распечатать матрицу Armadillo в gdb?

Я использую gdb для отладки моей программы на С++. Я использую числовую библиотеку броненосцев для определения своих матриц. У меня есть матрица броненосца, определенная так:

mat A = randu<mat>(5,5);

Можно ли распечатать всю матрицу при использовании отладчика gdb?


person Eddy    schedule 29.02.2012    source источник
comment
Недавний gdb (последний выпуск — GDB 7.4) может быть написан на Python. Вы это считали??   -  person Basile Starynkevitch    schedule 29.02.2012


Ответы (5)


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

Из-за того, что библиотека Armadillo основана на шаблонах, вам необходимо предоставить несколько собственных помощников:

#include <iostream>
#include <armadillo>

template<class Matrix>
void print_matrix(Matrix matrix) {
    matrix.print(std::cout);
}

//provide explicit instantiations of the template function for 
//every matrix type you use somewhere in your program.
template void print_matrix<arma::mat>(arma::mat matrix);
template void print_matrix<arma::cx_mat>(arma::cx_mat matrix);

int main() {
    arma::mat matrix = arma::randu(10,10);

    return 0;
}

Теперь вы можете легко вызвать print_matrix из gdb:

(gdb) call print_matrix<arma::Mat<double> >(matrix) 
   0.8402   0.4774   0.0163   0.5129   0.5267   0.5260   0.2383   0.5316   0.6879   0.9565
   0.3944   0.6289   0.2429   0.8391   0.7699   0.0861   0.9706   0.0393   0.1660   0.5886
   0.7831   0.3648   0.1372   0.6126   0.4002   0.1922   0.9022   0.4376   0.4401   0.6573
   0.7984   0.5134   0.8042   0.2960   0.8915   0.6632   0.8509   0.9318   0.8801   0.8587
   0.9116   0.9522   0.1567   0.6376   0.2833   0.8902   0.2667   0.9308   0.8292   0.4396
   0.1976   0.9162   0.4009   0.5243   0.3525   0.3489   0.5398   0.7210   0.3303   0.9240
   0.3352   0.6357   0.1298   0.4936   0.8077   0.0642   0.3752   0.2843   0.2290   0.3984
   0.7682   0.7173   0.1088   0.9728   0.9190   0.0200   0.7602   0.7385   0.8934   0.8148
   0.2778   0.1416   0.9989   0.2925   0.0698   0.4577   0.5125   0.6400   0.3504   0.6842
   0.5540   0.6070   0.2183   0.7714   0.9493   0.0631   0.6677   0.3540   0.6867   0.9110

Благодаря автодополнению вам нужно ввести всего несколько символов print_matrix<arma::Mat<double> >.

person rerx    schedule 31.03.2014
comment
+1. Это, должно быть, самый элегантный способ красиво распечатать матрицы броненосца. Однако выполнение команды -exec call print_matrix‹arma::Mat‹double› ›(matrix) в консоли отладки VS Code приводит к сбою моего сеанса отладки с сообщением об ошибке: Ошибка: GDB неожиданно завершил работу. ОШИБКА: GDB неожиданно завершил работу. Отладка будет прервана. Я думаю, что мне не хватает одного маленького кусочка головоломки, чтобы добраться туда. Любая идея от кого-либо? Я был бы очень признателен. - person rawpointer; 23.01.2021

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

> print *A.mem@5@5
$1 = {{0.84018771715470952, 0.39438292681909304,0.78309922375860586,0.79844003347607329, 0.91164735793678431},
{0.19755136929338396, 0.33522275571488902, 0.768229594811904, 0.27777471080318777, 0.55396995579543051}, 
{0.47739705186216025, 0.62887092476192441, 0.36478447279184334, 0.51340091019561551, 0.95222972517471283}, 
{0.91619506800370065, 0.63571172795990094, 0.71729692943268308, 0.14160255535580338, 0.60696887625705864}, 
{0.016300571624329581, 0.24288677062973696, 0.13723157678601872, 0.80417675422699042, 0.15667908925408455}}
person Claes Rolen    schedule 10.02.2017
comment
@RolenClaes +1. Большой! Без пухового раствора. Немного сложно прочитать вывод, но он не требует настройки или чего-то еще. Просто работает из коробки! Спасибо. - person rawpointer; 23.01.2021
comment
@RolenClaes Интересно, есть ли улучшенные решения с 2017 года. - person rawpointer; 23.01.2021
comment
@rawpointer Не то, чтобы я знал об улучшениях GDB, но вы всегда можете использовать красивую печать, см. sigpack. sourceforge.net/md_2-build.html - person Claes Rolen; 23.01.2021
comment
@RolenClaes Хорошо, понятно. Спасибо за ответ и ссылку. - person rawpointer; 23.01.2021

Наилучший вариант — использовать API-интерфейс gdb для Python для создания красивых принтеров для классы броненосцев. Он работает лучше, чем вызов функции C/C++, поскольку он всегда доступен (даже при отладке из основного файла, где нет запущенной программы). Кроме того, нет риска, что компоновщик отбросит функцию, когда она не используется в вашей программе (что сделает ее недоступной при отладке в gdb).

Красивый код принтера загружается (получается) из файла .gdbinit в вашей домашней папке. Он будет работать в gdb, запущенном в терминале, а также из IDE (при условии, что IDE не избегает загрузки файла .gdbinit).

В качестве примера предположим, что у вас есть следующие две матрицы

arma::mat m1{{1.1, 2.2,  3},
             {  4,   5,  6}, 
             {  7,   8,  9},
             { 10,  11, 12},
             { 13,  14, 15},
             { 16,  17, 18}};

arma::cx_mat m2{{1.1 - 1.1j, 2.2 - 7.7j, 3},
                {         4,          5, 6},
                {         7,          8, 9},
                {         10,        11, 12},
                {         13,        14, 15},
                {         16,        17, 18}};

Красивый принтер мог бы показать их как

м1

м2

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


Вот так в CLion отображаются матрицы m1 и m2.

m1 в CLion

м2 в CLion


Этот красивый принтер можно получить здесь. Есть несколько других вещей, таких как некоторые xmethods (python повторная реализация некоторых методов C++) и преобразование в массивы numpy.

Отказ от ответственности: я являюсь автором этих красивых принтеров.

person darcamo    schedule 10.10.2019

Вы можете вызывать функции C в gdb, поэтому вам просто нужна функция, которая печатает ваши объекты. Например:

(gdb) call printf("%.2f", 3.1428)
$7 = 4
(gdb) call fflush(stdout)
3.14$8 = 0
person Maxim Egorushkin    schedule 29.02.2012

Для тех, кто использует QtCreator, вы можете проверить значения из вашей IDE, выполнив расширение GDB с помощью помощников по отладке Python (возможно, другие IDE также поддерживают эту функцию).

Поместите следующий скрипт, например, в ~/debugHelpers.py

#!/usr/bin/python

import gdb      # gdb.Value()
import dumper   # dumper.Children()

def qdump__arma__Mat(d, value):
    array = value["mem"]
    cols = value["n_cols"]
    rows = value["n_rows"]
    maxDisplayItems = 50
    innerType = d.templateArgument(value.type, 0)
    p = gdb.Value(array.cast(innerType.pointer()))
    d.putItemCount(cols)
    d.putNumChild(cols)
    if d.isExpanded():
        numDisplayItems = min(maxDisplayItems, cols)
        with dumper.Children(d, numChild=cols,
               maxNumChild=numDisplayItems,
               childType="<column>",
               addrBase=p,
               addrStep=p.dereference().__sizeof__):
            for i in range(0, int(numDisplayItems)):
                with dumper.Children(d):
                    d.putItemCount(rows)
                    d.putNumChild(rows)
                    if d.isExpanded():
                        numDisplayItems = min(maxDisplayItems, rows)
                        with dumper.Children(d, numChild=rows,
                               maxNumChild=numDisplayItems,
                               childType=innerType,
                               addrBase=p,
                               addrStep=p.dereference().__sizeof__):
                            for j in range(0, int(numDisplayItems)):
                                d.putSubItem(j, p.dereference())
                                p += 1

И назовите это, добавив эту строку в свой ~/.gdbinit:

python exec(open('/<full_path>/debugHelpers.py').read())

или добавьте его из вашей IDE; в QtCreator используйте Инструменты > Параметры > Отладчик > GDB (вкладка) > Дополнительные помощники по отладке (внизу).

Этот конкретный скрипт вернет матрицу, упорядоченную по столбцам (естественное расположение памяти в моей архитектуре):

введите здесь описание изображения

Источники: Написание визуализаторов отладки для GDB/QtCreator 2.8

person Iban Cereijo    schedule 01.05.2015
comment
У меня возникли проблемы с тем, чтобы это работало в QtCreator 3.4.0. Все матрицы Armadillo получают значение <not accessible>. Я думаю, это может быть связано с тем, что мой gdb связан с Python 3. Есть ли у вас какие-либо предложения? Я добавляю скрипт, используя python exec(open(filename).read()), который совместим с Python 3 (execfile нет). - person Filip S.; 15.06.2015
comment
Я наконец-то заставил ваш скрипт работать после некоторой работы. В итоге я скомпилировал последнюю версию gdb (7.9.1), связал ее с Python 2 вместо 3 с помощью ./configure --prefix /usr/local/gdb-python2 --with-python, а затем использовал этот gdb в QtCreator. Мне также пришлось добавить import gdb и from dumper import * в начало вашего debugHelpers.py. Но мне бы все равно понравилась версия скрипта, которая работает с gdb и Python 3, так как сейчас Python 3 используется по умолчанию. - person Filip S.; 16.06.2015
comment
Привет @FilipSund, отлично!. Прежде чем я приму ваше редактирование: я попробовал сценарий, который вы предлагаете, с моим gdb с поддержкой Python2, но я не могу импортировать модуль «дампер». Можете ли вы обойти это с помощью Python 2? В противном случае я опубликую два варианта сценария. - person Iban Cereijo; 17.06.2015
comment
Да, я видел эту ошибку при запуске gdb в терминале. Но если вы добавите скрипт в QtCreator с помощью опции Extra Debugging Helpers, он будет работать, как задумано. Чтобы использовать его в gdb, я думаю, вам нужно добавить /usr/share/qtcreator/debugger/ (или аналогично) к пути python, например. добавив python sys.path.append("/usr/share/qtcreator/debugger/") в .gdbinit или запустив interpreter-exec console "python sys.path.append('/usr/share/qtcreator/debugger/')" в gdb перед загрузкой скрипта (это то, что делает QtCreator при запуске отладчика). Или, возможно, добавить его в скрипт проще! - person Filip S.; 18.06.2015
comment
Я обновил ответ, включая ваши изменения, это единственный вариант, который сейчас работает для меня с QtCreator 3.4.1 и GDB 7.7.1. Версия Python по-прежнему 2.7.9. - person Iban Cereijo; 03.07.2015
comment
После обновления до QtCreator 4.2.0 у меня возникли проблемы с этим помощником по отладке. Я получаю «недоступно» для всех матриц Armadillo. Любые идеи? - person Filip S.; 11.01.2017