Daniel Aarno
bishop@kth.se
Programsystemkonstruktion med C++
Övning 1
Översikt övning 1
Kompilering och länkning
Makefile
Preprocessordirektiv Funktioner
Funktionen main() Datatyper
Minneshantering Pekare och arrayer Vanliga slarvfel
Referenser
Statiska variabler
Kommentarer
Ett första program
En klass behöver både deklaration och definition
Deklaration i .h (.hh) och definition i .cpp (.cc) Private är förvalt
Student::learn()
Student::Student() Student::~Student()
Globala funktioner och variabler är OK.
main() är en global funktion
Macro (inleds med #) körs av preprocessorn
Ett första program (cont'd)
#ifndef _STUDENT_
#define _STUDENT_
#include <iostream>
#include <string>
using std::string;
class Student { private:
string knowledge;
public:
Student();
~Student() {};
void learn
(string info);
string speak();
};
#endif
#include "student.h"
Student::Student() {
knowledge="";
}
void Student::learn(string info)
{
knowledge += info;
}
string Student::speak() {
return knowledge;
}
student.h student.cpp
Ett första program (cont'd)
#include "student.h"
int main() {
Student s;
s.learn("bla bla bla");
std::cout << s.speak() << std::endl;
return 0;
}
main.cpp
För att köra programmet:
> g++ o ex1 main.cpp student.cpp
> ./ex1
bla bla bla
Kompilator och länkare
Kompilator och länkare (cont'd)
Filer kan kompileras var för sig till objektfiler (.o)
> g++ c file.cpp
> g++ c main.cpp
> ls
... file.o main.o
Flera objektfiler kan länkas samman till ett program (endast om main() är definerad)
> g++ o ex1 main.o file.o ...
> g++ o ex1_debug g O1 main.o file.o
debug optimeringsnivå 1
Beroenden (dependencies)
Om vi ändrar main.cpp räcker det att kompilera om den
Men om vi ändrar i student.cpp/h måste vi
eventuellt kompilera om både student.cpp och main.cpp (main.cpp beror på student.h)
Jobbigt hålla reda på beroenden
Långsamt att alltid kompilera om allt
”Intressanta” fel om allt som behöver kompileras
inte kompileras om
Makefiler
#variables CC = g++
FLAGS = g I~/c++kurs/student OBJ = main.o student.o
#rules
ex1: $(OBJ)
$(CC) $(FLAGS) o ex1 $(OBJ)
#don't forget tab!
main.o: main.cpp student.h
$(CC) $(FLAGS) c main.cpp student.o: student.h
$(CC) $(FLAGS) c student.cpp clean:
rm *.o ex1
Makefiler (cont'd)
#variables CC = g++
FLAGS = g I~/c++kurs/student OBJ = main.o student.o
SRC = main.cpp student.cpp
#rules
ex1: $(OBJ)
$(CC) $(FLAGS) o ex1 $(OBJ)
%.o: %.cpp
$(CC) $(FLAGS) c $*.cpp depend:
makedepend $(FLAGS) $(SRC) clean:
rm *.o ex1
http://www.gnu.org/manual/make3.79.1/html_chapter/make_toc.html
Preprocessorn
#include slår ihop filer innan kompilering
#ifndef ... #define ... #endif garanterar att en fil bara inkluderas en gång
// may be useful
#define MAX 10000 // dangerous
#define SQR1(A) A*A // less dangerous
#define SQR2(A) (A)*(A)
Funktioner
En funktion
Behöver inte defineras där den deklareras Behöver deklareras innan den används
int foo(int x); // declaration of foo int bar(int x) {
return foo(x); // call to foo }
int foo(int x) { return x; } // definition of foo
Kan överlagras
int foo(int x) { // code here ... } int foo(float x) { // code here ... }
Funktioner (cont'd)
En funktion
Kan ha argument med förvalt värde
int foo(float f,
int x = 0); //< OK int foo(float f = 0,
int x,
int y = 0); //< NOT OK
Kan vara inline
inline int sqr(int x) {
return x*x;
}
Funktioner (cont'd)
Fördelar med funktionen sqr()
Mer läsbar kod (samma anledning som macrot SQR) Ett ställe att ändra på
Alla anrop till sqr funkar likadant Löser problemet med macrot SQR
Det går ”slött” att använda funktioner. Argument måste
kopieras och programmets exekvering måste styras om.
Funktioner (cont'd)
inline är användbart för korta funktioner som används ofta
Overhead vid funktionsanrop är störst för små funktioner Inline gör att funktionsanropet ersätts med koden det
innehåller vid kompileringstilfället
För mycket inlining kan ge långsammare program och större filer
För mycket inlining ger långsammare kompilering
Funktioner (cont'd)
Funktionen main() är speciell Kan inte heta något annat
argc är antalet argument inkl. programmets namn
argv är en array av C-strängar med argumenten som gavs till programmet
argv[0] är programmets namn (tex /usr/bin/zip eller zip) main() är en global funktion och således inte del av någon klass
main() behöver inte deklareras
Funktioner (cont'd)
#include <iostream>
int main(int argc, char* argv[]) {
for(int i = 0; i < argc; i++) {
std::cout << argv[i] << std::endl;
} }
> g++ main.cc o main
> ./main hej 12 ./main
hej 12
>
main.cpp
Datatyper
Inbyggda datatyper
bool (true/false (1 byte)) char (1 byte)
int (plattformsberoende storlek) short
long
float (4 byte) double (8 byte) long double
void (ingenting)
Datatyper (cont'd)
Egna datatyper
typedef char* charPtr;
enum Fruit { apple, banana, orange };
struct { int x; int y; double d; };
class {int x; public: void foo(); };
union {int x, bool ok, double d };
Testa sizeof(T); för olika typer T (int, double,
charPtr osv)
Minneshantering
Automatiska objekt
Städas automatiskt upp när scopet är slut Snabb allokering på stacken
Mindre risk för slarvfel
void foo(Student s) { //< begin scope int x;
for(int i = 0; i < 5; i++) { //< begin scope int y = 2*i;
x = 3 + y;
} //< end scope (i,y)
} //< end scope (x,s)
Minneshantering
Dynamiska objekt
Heap större än stack
Arrayers längd kan bestämmas i run-time Objekt kan leva utanför scope där de skapas
void foo(int nmemb) {
int *xPtr;
// Allocate array of nmemb ints xPtr = new int[nmemb];
// do stuff, then
// delete memory allocated by new[]
delete[] xPtr;
}
Minneshantering
CODE/TEXT
Själva programkoden och konstanta variabler
DATA
Statiska (static) initialiserade variabler
BSS
Statiska icke initialiserade variabler
STACK
Automatiskt allokerade variabler vid körning Returvärden och returadresser
4kB på Linux, kan växa till 2MB (default)
Pekare och arrayer
void foo(Student *studPtr) {
int *ptr, i; //< ptr is ptr to int, i is int int* x, y; //< x is ptr to int, y is int
ptr = &i; //< ptr now holds address //< of i (e.g. 0xbfffff24) *ptr = 5; //< assign 5 to i
x = ptr; //< x now also points to i;
cout << *x << endl; //< would print 5 (*studPtr).learn(”something”);
studPtr>learn(”more”);
ptr = new int; //< ptr now holds adr
//< of an int on the heap ptr = &y; //< error no way to access
//< memory on heap anymore
}
Pekare och arrayer (cont'd)
void foo(float f) {
char array[4711]; //< array of 4711 uninitialized chars int ary[] = {1,2,5}; //< array of 3 initialized ints
// same as const char str[] = {'h','e','j',0};
char str[] = ”hej”;
char* ptr = 0; //< char pointer to nothing
const float *fPtr; //< The memory pointed to by f is //< readonly
float * const fcPtr=f; //< The pointer f is readonly ptr = array; //< same as ptr = &array[0];
ptr[4] = 'x'; //< set fifth element of array to x;
*(ptr + 4) = 'y'; //< same thing, but to y
ptr = new char[512]; //< dynamically allocated array }
Vanliga slarvfel
void foo(int *p) { delete p;
}
int* bar() { int x=1;
return &x; // oops!
}
void fun() {
int* p1, p2; // p2 is normal int not pointer int *p3 = new int[2];
int *p4 = new int[2];
p3 = p4; // MEMORY LEAK!
foo(p3); // destruction of p3 (and p4) int x = p4[1]; // error (segfault if LUCKY) }
Referenser
Alias för ett objekt Som en pekare vars adress inte får ändras Måste referera till ett objekt (inte NULL)
Snabbare skicka referens än objekt
void iswap(int &i1, int &i2) {
int tmp = i1;
i1 = i2;
i2 = tmp;
}
void main() {
int i = 5;
int &iRef = i;
int *iPtr = &i;
iRef++;
// i, iRef and
// *iPtr is now 6
}
Statiska variabler
void foo()
{ static int i = 5;
cout << i++ << endl;
}
int main() {
foo();
foo();
foo();
}
> ./static 5
6 7
>
static.cpp
Kommentarer
Funktionskommentarer förklarar användning (.h)
/**
* Send a signal to the task.
*
* @param signal The signal to send (i.e. SIGINT) * @return true on success, false on failiure.
*/
bool sigSend(int signal);
Procedurkommentarer förklarar implementationen (.cpp)
/* getline reads one line from stdin and stores it in * the given buffer. The newline is stored.
* The given buffer must be big enough to store the * trailing \0 (i.e. it must be at least one bigger * than nmax).
*/
void getline (char buf[], int nmax, int *nread) { //function implementation...