Материалы к занятиям: https://maxxk.github.io/programming-semester-5/
email:
В дисплейных классах рекомендуется просматривать в браузере Firefox.
В нём установлено расширение NoScript, обратите внимание на инструкцию, иначе значительная часть сайтов не будет работать.
Приоритеты:
Рекомендации из Mozilla Style Guide:
if (...) {
...
} else if (...) {
} else {
}
while (...) {
}
do {
} while (...);
for (...; ...; ...) {
}
int a = 0,
b = 3;
int i, j, k;
double* d;
switch (...) {
case 1: {
// When you need to declare a variable in a switch, put the block in braces
int var;
break;
}
case 2:
...
break;
default:
break;
}
./myprog -n 10 -f abs_i-j -v
Функция getopt
:
#include <unistd.h>
extern char *optarg;
extern int optind;
extern int optopt;
extern int opterr;
extern int optreset;
int
getopt(int argc, char * const argv[], const char *optstring);
optstring
: строка с последовательностью букв — имён аргументов командной строки. Если после имени указано двоеточие, соответствующий аргумент командной строки имеет параметр; если нет — это просто флаг.
./myprog -n 10 -f abs_i-j -v
#include <unistd.h>
struct Params {
int size; // размер массива
char* formula; // формула заполнения
char verbose; // отладочный вывод
}
int main(int argc, char** argv) {
struct Params params;
int opt;
while ((opt = getopt(argc, argv, "vn:f:")) != -1) {
switch (opt) {
...
}
}
}
case 'n': {
char *next;
params.size = strtol(optarg, &next, 10);
}
Подробнее про getopt
:
Не следует использовать:
time()
— «календарное» время; точность — 1 секунда; между двумя измерениями может измениться произвольным образом, вплоть до перехода назад (переход на зимнее время; перевод часов вручную)clock()
— точность — 1 микросекунда; 32-битный счётчик, переполняется за час с небольшим.gettimeofday
— «календарное» время, может идти назадНужно использовать:
clock_gettime(CLOCK_MONOTONIC)
— таймер с наносекундным разрешением; предназначен именно для измерения промежутков времени в программе с высокой точностью (специфичен для Linux).
#include <unistd.h>
Прототип:
struct timespec {
time_t tv_sec; // секунды
long tv_nsec; // наносекунды
} // Объявлено в unistd.h
int clock_gettime(clockid_t clk_id, struct timespec *tp)
Значения clockid_t
:
CLOCK_MONOTONIC
— реальное время от произвольной точки отсчёта (можно использовать только как разность);CLOCK_PROCESS_CPUTIME_ID
— использование процессорного времени;CLOCK_THREAD_CPUTIME_ID
— использование процессорного времени потокомПоследние два значения понядобятся в третьей задаче.
Компилировать лучше с -std=c99
, т.к. в стандартах C89 и C90 нет типа long long
. Источник, там же есть реализация для Mac OS X.
#include <time.h>
unsigned long long currentTimeNano() {
struct timespec t;
clock_gettime(CLOCK_MONOTONIC, &t);
return t.tv_sec*1000000000 + t.tv_nsec;
}
unsigned long long currentTimeMillis() {
struct timespec t;
clock_gettime(CLOCK_MONOTONIC, &t);
return t.tv_sec*1000 + t.tv_nsec/1000000;
}
long long time = 0;
time = currentTimeNano();
Solve(n, a, b, tmp_double, tmp_int, debug);
time = currentTimeNano() - time;
CheckAnswer(n, a, b);
Этот пример должен собираться в дисплейных классах с параметрами компилятора по умолчанию. Источник
#include <time.h>
struct timespec diff(struct timespec start, struct timespec end)
{
struct timespec temp;
if ((end.tv_nsec-start.tv_nsec)<0) {
temp.tv_sec = end.tv_sec-start.tv_sec-1;
temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
} else {
temp.tv_sec = end.tv_sec-start.tv_sec;
temp.tv_nsec = end.tv_nsec-start.tv_nsec;
}
return temp;
}
struct timespec time_start, time_end;
clock_gettime(CLOCK_MONOTONIC, &time_start);
Solve(n, a, b, tmp_double, tmp_int, debug);
clock_gettime(CLOCK_MONOTONIC, &time_end);
time_end = diff(time_start, time_end);
Сценарии использования отладчика:
Для отладки программу нужно скомпилировать с отладочной информацией (ключ -g
) без оптимизации (g++
— аналогично):
gcc -g myprog.c main.c
Запуск отладчика
программа без аргументов
gdb ./a.out
# Вместо ./a.out
аргументы при запуске
gdb --args ./a.out -f 2 -n 1000
# Вместо ./a.out --formula 2 -s 1000
После запуска отображается командная строка gdb.
Аргументы можно изменить в командной строке gdb:
set args -f 1 -n 500
show args # Показать текущие аргументы
run
(r
) — запустить программу; в случае исключения выполнение останавливается на строке, на которой исключение произошло:
(gdb) r
Program received signal SIGFPE, Arithmetic exception.
0x08048681 in divint(int, int) (a=3, b=0) at crash.c:21
21 return a / b;
quit
(q
) — выйти из отладчика (если выполнение программы было прервано, отладчик запросит подтверждение)list
(l
) — напечатать «окрестность» текущей строки исходного кодаprint <expression>
(p <expr>
) — вывести значение выражения (можно использовать арифметические операторы, получение элемента массива, по-моему даже вызовы функций)
where
(backtrace
, bt
) — показать стек вызовов функций:
(gdb) where
#0 0x08048681 in divint(int, int) (a=3, b=0) at crash.c:21
#1 0x08048654 in main () at crash.c:13
frame <n>
(up
) — перейти на указанный уровень в стеке вызовов (чтобы посмотреть значения переменных в вызывающей функции)
при нажатии Ctrl+C выполнение программы приостанавливается
break <location>
(b <loc>
) — установить точку останова в указанной локации:
delete
— удалить все точки остановаclear <location>
— удалить точку останова в указанной локацииnext
(n
) — выполнить до следующей строки программыstep
(s
) — выполнить одну строку, «проваливаясь» в вызываемые функцииcontinue
(c
) — продолжить выполнение программы (до следующей точки останова или исключения)Valgrind — средство динамического (= во время выполнения) анализа программ.
Позволяет анализировать, в частности, следующие показатели:
# Вместо ./a.out --fun 1 --size 2
valgrind ./a.out --fun 1 --size 2
==19182== Invalid write of size 4
==19182== at 0x804838F: f (example.c:6)
==19182== by 0x80483AB: main (example.c:11)
==19182== Address 0x1BA45050 is 0 bytes after a block of size 40 alloc'd
==19182== at 0x1B8FF5CD: malloc (vg_replace_malloc.c:130)
==19182== by 0x8048385: f (example.c:5)
==19182== by 0x80483AB: main (example.c:11)
# ...
==19182== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==19182== at 0x1B8FF5CD: malloc (vg_replace_malloc.c:130)
==19182== by 0x8048385: f (a.c:5)
==19182== by 0x80483AB: main (a.c:11)
-n
(размер матрицы, число)-f
(имя формулы, строка);-i
(имя входного файла, строка);-o
(имя выходного файла, строка);-v
(отладочный вывод, флаг).stdin
и stdout
, соответственно)если аргументы корректны и задан флаг отладочного вывода, выводить обработанные аргументы в следующем виде:
Formula: ... (или "no")
Matrix size: ...(или "from file")
Input file: ... (или "stdin")
Output file: ... (или "stdout")
Verbose mode: ...