перечисляет для каждой функции другие функции, вызывающие данную. Звучит не очень понятно, но на самом деле все просто. Далее приведен пример:
19 display_list {prcc.c 1056}
20 show_all_lists {prcc.c 1070}
21 exit {}
22 main {prcc.c 70}
23 show_all_lists {prcc.c 1070}
24 usage {prcc.c 59}
25 ...
74 printf {}
75 display_list {prcc.c 1056}
76 maketag {prcc.c 4 87}
77 show_all_lists {prcc.c 1070}
78 main {prcc.c 70}
79 ...
99 usage {prcc.c 59}
100 main {prcc.c 70}
В примере показано, что функцию
exit
, например, вызывают функции
main
,
show_all_lists
и
usage
.
Выполнение профилирования с помощью prof/gprof
Методика, зачастую полезная при попытках выяснить проблемы снижения производительности программы, называется профилированием выполнения (execution profiling). Профиль программы, обычно поддерживаемый специальными опциями компилятора и вспомогательными программами, показывает, где программа тратит время.
Программа
prof
(и ее эквивалент в проекте GNU,
gprof
) выводит отчёт из файла трассировки выполнения, который формируется во время выполнения профилируемой программы. Профилируемый исполняемый файл создается с помощью флага компилятора
– p
(для
prof
) или флага
– pg
(для
gprof
).
$ cc -pg -о program program.с
Программа компонуется со специальной библиотекой С, и в нее включается контрольный код. В конкретных системах он может отличаться, но общая цель — такая организация программы, которая позволяет часто прерывать выполнение и записывать этап выполнения. Контрольные данные записываются в файл mon.out (gmon.out для
gprof
) в текущем каталоге.
$ ./program
$ ls -ls
2 -rw-r--r-- 1 neil users 1294 Feb 4 11:48 gmon.out
Программа prof/gprof читает эти контрольные данные и выводит отчет. См. подробности, касающиеся опций программы, в интерактивном справочном руководстве. Далее в качестве примера приведен вывод (сокращенный) программы gprof.
cumulative self self total
time seconds seconds calls ms/call ms/call name
18.5 0.10 0.10 8664 0.01 0.03 doscan [4]
18.5 0.20 0.10 mcount (60)
14.8 0.28 0.08 43320 0.00 0.00 _number [5]
9.3 0.33 0.05 8664 0.01 0.01 _format_arg [6]
7.4 0.37 0.04 112632 0.00 0.00 _ungetc [8]
7.4 0.41 0.04 8757 0.00 0.00 _memccpy [9]
7.4 0.45 0.04 1 40.00 390.02 _main [2]
3.7 0.47 0.02 53 0.38 0.38 _read [12]
3.7 0.49 0.02 w4str [10]
1.9 0.50 0.01 26034 0.00 0.00 _strlen [16]
1.9 0.51 0.01 8664 0.00 0.00 strncmp [17]
Проверки
соблюдения условий
Несмотря на то, что вставка на этапе разработки программы с помощью условной компиляции отладочного кода, такого как вызовы
printf
, распространена, иногда оставлять такие сообщения в поставляемой программе непрактично. Но часто проблемы возникают во время работы программы из-за некорректных допущений или исходных данных, а не из-за ошибок кодирования. Это события, которых "не может быть никогда". Например, функция может быть написана в расчете на то, что ее входные параметры будут в определенном диапазоне. Если передать ей некорректные данные, она может сделать некорректной работу всей системы.
В тех случаях, когда внутренняя логика системы нуждается в подкреплении, X/Open предоставляет макрос
assert
, применяемый для проверки правильности исходных данных и остановки выполнения программы в противном случае.
#include <assert.h>
void assert(int expression)
Макрос
assert
вычисляет выражение и, если оно не равно нулю, выводит некоторую диагностическую информацию о стандартной ошибке и вызывает функцию
abort
для завершения программы.
Заголовочный файл assert.h определяет макросы в зависимости от определения флага
NDEBUG
. Если
NDEBUG
определен во время обработки заголовочного файла,
assert
определяется по существу как ничто. Это означает, что вы можете отключить проверки заданных выражений во время компиляции, компилируя с опцией
– DNDEBUG
или вставив перед включением файла assert.h строку
#define NDEBUG
в каждый исходный файл.
Этот метод применения порождает проблему. Если вы используете
assert
во время тестирования, но отключите макрос в рабочем коде, в вашем рабочем коде может оказаться менее строгая проверка, чем применявшаяся в процессе его тестирования. Обычно макросы
assert
не оставляют включенными в рабочем коде — вряд ли вам понравится рабочий код, предоставляющий пользователю недружелюбное сообщение
assert failed
и останавливающий программу. Быть может, лучше написать свою отслеживающую ошибки подпрограмму, которая проверяет выражение, использовавшееся в макросе, но не нуждается в полном отключении в рабочем коде.