Материалы к занятиям: 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.hint 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:13frame <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: ...