русс | укр

Мови програмуванняВідео уроки php mysqlПаскальСіАсемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование


Linux Unix Алгоритмічні мови Архітектура мікроконтролерів Введення в розробку розподілених інформаційних систем Дискретна математика Інформаційне обслуговування користувачів Інформація та моделювання в управлінні виробництвом Комп'ютерна графіка Лекції


Шановні українці! Матеріал був перекладений з російської мови. Тому можуть бути незначні помикли...

G++ Компілятор | gdb

Переробимо нашу предидущую програму, але на цей раз вже напишемо її на C++. Створити новий каталог проекту kalkulcpp, а в ньому три файлу: problem.h, problem.cpp, main.cpp.


problem.h

//------------------------------
#ifndef PROBLEM_H_
#define PROBLEM_H_
#include <string>
using namespace std;
class CProblem
{
private:
float Numeral;
float SecondNumeral;
string Operation;
float Result;
string Error;
bool Calculate();

public:
void SetValues();
void Solve();
};
#endif /*PROBLEM_H_*/

 

problem.cpp

//-------------------------------------------
#include <iostream>
#include <cmath>
#include "problem.h"

using namespace std;

void CProblem::SetValues()
{
cout << "Число: ";
cin >> Numeral;
cout <<"Арифметичне дію (+,-,*,/,pow,sqrt,sin,cos,tan): ";
cin >> Operation;
}

bool CProblem::Calculate()
{
if(Operation == "+")
{
cout << "Другий доданок: ";
cin >> SecondNumeral;
Result = Numeral + SecondNumeral;
return true;
}
else if(Operation == "-")
{
cout << "Другий доданок: ";
cin >> SecondNumeral;
Result = Numeral - SecondNumeral;
return true;
}
else if(Operation == "*")
{
cout << "Множник: ";
cin >> SecondNumeral;
Result = Numeral * SecondNumeral;
return true;
}
else if(Operation == "/")
{
cout << "Дільник: ";
cin >> SecondNumeral;
if(SecondNumeral == 0)
{
Error = "Помилка: ділення на нуль.";
return false;
}
else
{
Result = Numeral/SecondNumeral;
return true;
}
}
else if(Operation == pow "")
{
cout << "Ступінь: ";
cin >> SecondNumeral;
Result = pow(Numeral,SecondNumeral);
return true;
}
else if(Operation == "sqrt")
{
Result = sqrt(Numeral);
return true;
}
else if(Operation == "sin")
{
Result = sin(Numeral);
return true;
}
else if(Operation == "cos")
{
Result = cos(Numeral);
return true;
}
else if(Operation == "tan")
{
Result = tan(Numeral);
return true;
}
else
{
Error = "Помилка вводу дії.";
return false;
}
}

void CProblem::Solve()
{
if(Calculate() == true)
cout << Result << "\n";
else
cout << Error << "\n";
}

 

main.cpp

 

//------------------------------------------
#include <iostream>
#include "problem.h"

using namespace std;

int main(void)
{
CProblem *Problem;
Problem = new CProblem;
Problem->SetValues();
Problem->Solve();
delete Problem;
return(0);
}

 

Для збірки програм на C++ в наборі GNU є компілятор - G++. Він відрізняється від GCC тим, що за замовчуванням підключає не стандартну бібліотеку C, а стандартну бібліотеку C++. Всі прапори і опції у G++ точно такі ж, як і у GCC.

Скористаємося компілятором G++.


g++ problem.cpp main.cpp -o kalkul

Зверніть увагу, що ніяких додаткових бібліотек ми не підключали. Це означає, що математичні функції входять в стандартну бібліотеку C++. Взагалі, в тих випадках, коли програма написана на C++, рекомендується використовувати саме G++.

Ви вже знаєте, що збирати програми таким простим способом можна тільки в навчальних цілях. У професійній роботі ваші проекти будуть включати велику кількість файлів, і вам доведеться користуватися утилітою make.

Створимо Makefile:

 

kalkul: problem.o main.o
g++ problem.o main.o-o kalkul
problem.o: problem.cpp problem.h
g++ -c problem.cpp
main.o: main.cpp problem.h
g++ -c main.cpp
clean:
rm-f kalkul problem.o main.o
install:
cp kalkul /usr/local/bin/kalkul
uninstall:
rm-f /usr/local/bin/kalkul

 

І зберемо цю програму знову, але вже «правильним» способом:

make

Інсталюємо її, попередньо зайшовши в систему, як суперползователь:

su
make install
exit

 

Деинсталлируем:

su
make uninstall
exit

 

І очистимо дистрибутив:

make clean

 

 

Знайомство з відладчиком gdb

Помилки, на жаль, трапляються в будь-якій програмі, яким би крутим професіоналом її розробник не був. Тому, подобається це вам чи ні, користуватися відладчиком вам все одно доведеться. Життя змусить. І чим більше часу ви зараз витратите на вивчення роботи з ним, тим більше часу це заощадить вам надалі.

Ми розглянемо GDB, що входить в комплект програм GNU.

Для того, щоб користуватися ним, потрібно спочатку скомпілювати програму так, щоб її двійковий файл містив налагоджувальну інформацію. Ця інформація включає в себе, зокрема, опис відповідностей між адресами виконуваного коду і рядками у вихідному коді.

Така компіляція досягається шляхом додавання прапора-g до команди на компіляцію. Н апример, якщо б ми збирали програму kalkul без застосування Makefile, ми б дали таку команду:

g++ main.cpp problem.cpp -o kalkul-g

Якщо ж ми користуємося командою make, то треба поставити опцію CFLAGS=-g. Тоді всі команди на компіляцію, що містяться в Make-файлі, автоматично отримають прапор-g.

Або змініть файл Makefile, добавивь опцію-g (для програми З++):

 

kalkul: problem.o main.o
g++ -g problem.o main.o-o kalkul
problem.o: problem.cpp problem.h
g++ -g-c problem.cpp
main.o: main.cpp problem.h
g++ -g-c main.cpp
clean:
rm-f kalkul problem.o main.o
install:
cp kalkul /usr/local/bin/kalkul
uninstall:
rm-f /usr/local/bin/kalkul

 

Або для програми, написані на C:

kalkul: calculate.o main.o
gcc-g calculate.o main.o-o kalkul-lm
calculate.o: calculate.c calculate.h
gcc-g-c calculate.c
main.o: main.c calculate.h
gcc-g-c main.c
clean:
rm-f kalkul calculate.o main.o
install:
cp kalkul /usr/local/bin/kalkul
uninstall:
rm-f /usr/local/bin/kalkul

 

Давайте візьмемо програму, яку ми створили з файлів main.cpp, problem.cpp і problem.h (ми тоді називали цей каталог проекту kalkulcpp). У нас Makefile вже сформовано. Скористаємося ним.

Очистимо пакет від результатів попередньої збирання:

make clean

Зберемо програму знову, але вже з включенням налагоджувальної інформації:

 

make CFLAGS=-g

Або зберемо програму зі зміненим Makefile (рекомендується цей варіант):

make

Запустимо GDB, завантаживши в нього нашу програму для налагодження:

gdb/.kalkul

Щоб запустити програму всередині відладчика,дається команда run:

 

run

Щоб переглянути вихідний код, дається команда list:

list

Якщо дати цю команду без параметрів, то вона перші дев'ять рядків коду головного файлу (тобто такого, в якому є функція main). Щоб переглядати файл далі, треба знову набирати list. Щоб побачити конкретні строки, треба вказати два параметри: з якою рядка починати перегляд, і з якою рядка закінчувати.

list 12,15

Щоб переглянути інші файли проекту, треба перед номерами рядків вказати назву файлу і відокремити його від номерів рядків двокрапкою.

list problem.cpp:20,29

Поставимо точку зупину на рядку номер 21. Точка зупинки - це мітка, яка вказує, що програма, дійшовши до цього місця, повинна зупинитися.


list problem.cpp:20,27
break 21

Подивитися, де ви поставили точки зупину, можна за допомогою команди info breakpoints.


info breakpoints

(При бажанні можна замість номера рядка вказати назву функції,тоді програма зупиниться перед входом у функцію.)

Запустимо програму.


run

Введемо перше число 5 і знак математичного дії « + ». Програма дійде до точки зупину і зупиниться, вивівши нам рядок, у якій ця точка розташована.

Нам, звичайно, цікаво знати,в якому саме місці ми зупинилися, і що програма вже встигла виконати. Даємо команду backtrace.


backtrace

Налагодження видає нам наступну інформацію:


#0 CProblem::Calculate (this=0x804b008) at problem.cpp:21
#1 0x08048e00 in CProblem::Solve (this=0x804b008) at problem.cpp:93
#2 0x08048efc in main () at main.cpp:15

Це означає, що ми знаходимося всередині виконує функції Calculate, що є функцією-членом класу CProblem. Вона була викликана функції Solve того ж класу, а та, у свою чергу, з функції main. Таким чином, команда backtrace показує весь стек що викликаються функцій від початку програми до поточного місця. Подивимося, чому ж одно на цьому етапі значення змінної Numeral.


print Numeral

І нам відразу виводиться число 5, яке ми і вводили в програму. (Значення, введене нами з клавіатури, присвоилось саме цієї змінної.)

Якщо ми замість print будемо користуватися командою display, то величина цієї змінної буде показуватися кожен раз, коли програма зупиняється, без спеціальної вказівки.


display Numeral

Додамо ще одну точку зупину на рядку 25 файлу problem.cpp.


break problem.cpp:25

Продовжимо виконання програми.


continue

Команда Continue продовжує виконання програми з поточного адреси. Якщо б ми набрали run, програма почала би виконуватися з початку. Оскільки на рядку 24 є команда cin >> SecondNumeral, то нам доведеться ввести другий доданок. Введемо, наприклад,число 2. Після цього програма знову зупиниться на рядку 25 (наша друга точка зупинки).

Подивимося, чому рівні значення наших змінних Numeral, SecondNumeral і Operation. Якщо ви пам'ятаєте, саме такі змінні ми оголошували в класі CProblem.


print Numeral
print Operation
print SecondNumeral

У нас вийде 5, « + », 2. Так і повинно бути. Але давайте тепер «передумаем» і краще присвоїмо змінної SecondNumeral значення 4. GDB дозволяє прямо під час виконання програми змінити значення будь-який змінної.


set SecondNumeral=4

Якщо не віримо, що її значення змінилося,можна перевірити.


print SecondNumeral

Тепер ми ожидаетм, що результат буде 9. Давайте виконаємо програму до кінця.


continue

Результат дійсно дорівнює 9.

тепер Давайте заберемо наші точки зупину. Ми, здається, створили дві таких точки. Але це можна перевірити.


info breakpoints

Видалимо їх.


delete 1

delete 2

У нас не повинно залишитися ні однієї точки зупину. Перевіряємо.


info breakpoints

Дійсно не залишилося жодної.

Тепер давайте покроково пройдемо всю програму (благо, вона у нас невелика).

Поставимо точку зупину на десятій рядку головного файлу.


break main.cpp:10

Запустити програму


run

Дійшовши до десятої рядки, вона зупиниться. Тепер проходимо її, зупиняючись на кожній сходинці, з допомогою командиstep.r


step

Щоб не набирати кожен раз s-t-e-p, можна просто ввести літеру s. Як тільки програма доходить до команди Problem->SetValues(), вона відразу переходить у файл problem.cpp, де знаходиться визначення функції-члена CProblem::SetValues() і проходить код цієї функції. Те ж саме, коли вона дійде до виклику Problem->Solve().

Щоб при виконанні функції, програма не входила до неї, а продовжувала далі виконуватися лише на поточному рівні стека, замість step дається команда next або просто. r


next

Якщо ми увійшли у функцію, але не хочемо далі проходити її за кроками, а хочемо, щоб вона відпрацювала і повернула нас на попередній рівень стека (тобто, назад у функцію, яка викликала її), ми користуємося командою finish.


finish

Таким чином, можна переглянути, як виконується вся програма або будь-яку ділянку програми. На кожному кроці можна перевіряти значення будь-який змінної. Щоб перестати проходити програму по кроках і запустити її до кінця, треба дати команду continue.

Дамо короткий список найбільш часто зустрічаються команд налагоджувача GDB. За більш детальною інформацією звичайно, ви завжди можете звернутися до вбудованому опису програми (info gdb) або керівництвом користування (man gdb).

 

 

Команди налагоджувача GDB


backtrace - виводить весь шлях до поточної точки зупину, тобто назви всіх функцій, починаючи від main();
іншими словами, виводить весь стек функцій;

break - встановлює точку зупинки; параметром може бути номер рядка або назва функції;

clear - видаляє всі точки зупину на поточному рівні стека (тобто в поточній функції);

continue - продовжує виконання програми від поточної точки до кінця;

delete - видаляє точку зупинки або контрольне вираз;

display - додає вираз у список виразів, значення яких відображаються кожен раз при зупинці програми;

finish - виконує програму до виходу з поточної функції; відображає повертає значення,якщо таке є;

info breakpoints - виводить список всіх наявних точок зупину;

info watchpoints - виводить список всіх наявних контрольних виразів;

list - показати вихідний код; в якості параметра передаються назва файлу первинного коду, потім, через двокрапку,
номер початкової і кінцевої рядка;

next - покрокове виконання програми, але, на відміну від команди step, не виконує покроково викликувані функції;

print - виводить значення якого-або вирази (вираз передається в якості параметра);

run - запускає програму на виконання;

set - встановлює нове значення змінної

step - покрокове виконання програми;

watch - встановлює контрольне вираз, програма зупиниться, як тільки значення контрольного вираження зміниться;

 


Опис приклад

Цей приклад ми будемо використовувати у всіх інших статтях.

Легенда: Слони на водопої

У більшості африканських національних парків існують значні екологічні проблеми, викликані тим, що щільність тваринного населення перевищує можливості природного середовища на обмеженою території. Одним з найбільш сильних факторів, що впливають на екологію, є Слони. Для дотримання природного балансу череди Слонів потрібна досить велика територія, що не збігається з межами національних парків, тому життя Слона в національному парку являє собою нескінченний ланцюг проблем, головна з яких - задоволення проблем у воді у посушливий сезон. Оскільки Слони - надзвичайно привабливі тварини з яскраво вираженими індивідуальностями, ми приймаємо їх проблеми особливо близько до серця.

В нашій "легендою" стадо Слонів шукає воду в савані. Умови пошуку споживання води уточнюються в кожній задачі окремо. Кожен Слон видається окремим процесом або ниткою, але програми, які працюють у процесах-Слонах, ідентичні. Поряд з процесами-Слонами, є процес-монітор, який є батьківським для всіх процесів-Слонів. Процес-монітор у всіх завданнях здійснює породження процесів-Слонів, загальне управління ними, а також забезпечення взаємодії між ними при необхідності. Таким чином, процес-монітор являє собою "колективний розум" слонячого стада, ми назвали його Ганеша.

 

Кожен окремий Слон характеризується такими атрибутами, як:

вік (від віку може залежати, по-перше, час, що витрачається на пошук води: чим старше Слон, тим швидше він знаходить воду, по-друге, час споживання води: чим старше Слон, тим швидше він п'є);

вага в тоннах (чим важче Слон, тим більше води йому потрібно).

Програмне подання Слона описується у файлі elephant.h, який ми включаємо в програми всіх наших прикладів.

 

У всіх прикладах ми також працюємо з одним і тим же стадом - масивом Слонів. Стадо визначається також у файлі elephanth.h, який ми включаємо в усі приклади.

Значна частина програмних кодів прикладів кожної роботи буде переноситися в наступні роботи. Тому такі фрагменти коду оформлені як заголовочні файли (.h-файли).

За змістом завдань "діяльність" Слонів (пошук води в савані і насичення водою) займає деякий час. При цьому зайнято реальної діяльністю, а не очікуванням (навіть якщо в програмній моделі результати цієї діяльності не розглядаються). У термінах програмування це означає, що процес, виконує цю "діяльність", займає центральний процесор. Тому для моделювання такий "діяльності" не застосовуються системні виклики типу sleep, nanosleep, так як вони забезпечують затримку процесу в стані очікування, без використання центрального процесора. Для "зайнятого очікування" нами створено дві функції:

функція a0wait забезпечує зайняте очікування протягом заданого інтервалу часу;

функція a1wait забезпечує зайняте очікування протягом випадкового інтервалу часу.

Вихідні тексти цих функцій доступні для вас в каталозі /home/OS/Metod/Lab_2010/Part_2/OS_Examples у файлі common/wait.c.

В тому ж каталозі у файлі curtime.c визначена допоміжна функція curtime, позволяющяя отримати символьне представлення поточного часу.

Переглядів: 1624

Повернутися в зміст:ОС Linux




Онлайн система числення Калькулятор онлайн звичайний Науковий калькулятор онлайн