NPRG 041 Programovn v C Programovn v C

  • Slides: 45
Download presentation
NPRG 041 Programování v C++ Programování v C David Bednárek Filip Zavoral

NPRG 041 Programování v C++ Programování v C David Bednárek Filip Zavoral

C vs. C++ � Vývoj ◦ ◦ ◦ ◦ � 1970 -3 1978 1983

C vs. C++ � Vývoj ◦ ◦ ◦ ◦ � 1970 -3 1978 1983 1985 1998 1999 2011+ první verze C, společný vývoj s UNIXem, jádro v C Kerninghan, Ritchie: The C Programming Language Rick Mascitti: poprvé název C++ Stroustrup: The C++ Programming Language ISO/ANSI norma C++ ISO/ANSI norma C - 'C 99' C++11/14/17 � zásadní rozšíření jazyka - lambda, r-values, generic prog. , . . . Proč C v 21. století ◦ ◦ jádra OS, drivery, knihovny GPU, many-core embedded devices, 'pračky' údržba sw

C++ jako ostrá nadmnožina C. . . neboli co v C není � OOP

C++ jako ostrá nadmnožina C. . . neboli co v C není � OOP ◦ classes, inheritance, member functions, constructors and destructors, virtual functions, access control, pointers to members, static members � Syntax ◦ templates, smart pointers, exceptions, references, overloading, default arguments, namespaces, new/delete, casting, friend, inline, RTTI, auto, lambda, rvalues, concepts, . . . � Libraries ◦ containers, iterators & algorithms ◦ strings ◦ streams

Odlišnosti C a C++ � bool b = true; _Bool b = TRUE; �

Odlišnosti C a C++ � bool b = true; _Bool b = TRUE; � � C 99 typedef enum bool_ { FALSE, TRUE} bool; bool b = TRUE; int b 2 = a > 1; struct & enum tags struct S { int x; }; typedef struct S_ { int x; } S; S s; struct S s; implicitní konverze - enum, void * enum E { NULA }; E e = NULA; int x = (int)e; int* p = (int*)malloc(sizeof(int)); � C ⊈ C++ enum E { NULA }; enum E e = NULA; int x = e; int* p = malloc(sizeof( int)); main - return 0; int main() {. . . } int main() {. . . return 0; }

Pole a ukazatele, aritmetika ukazatelů � � � T a[n]; T *p = &a[i];

Pole a ukazatele, aritmetika ukazatelů � � � T a[n]; T *p = &a[i]; p+j; p+=j; ++p p-j p 1 -p 2 int a[5]; int *p; a[2] = 20; p = &a[2]; pole prvků typu T ukazatel p ukazuje na prvek pole přičtení - posun o j prvků v rámci pole stejně jako iterátory odečtení - posun zpět odečtení ukazatelů - počet prvků mezi a 0 1 2 3 4 ? ? 20 ? ? 30 ? p reference na prvek pole a[0] = *p - 15; ++p; *p = 30; 5 ? 20 p inkrementace ukazatele posun na další prvek

Pole a ukazatele, aritmetika ukazatelů � p = &a[1]; *(p+3) = 40; � Operátor

Pole a ukazatele, aritmetika ukazatelů � p = &a[1]; *(p+3) = 40; � Operátor [] � � � p[i] *(p+i) &p[i] p+i 5 ? 20 přičtení čísla k ukazateli posun o n prvků indexování pole (ukazatele) je 'jen' jiný zápis přístupu přes ukazatel identifikátor pole je ukazatel na svůj nultý prvek � a &a[0] � Automatické konverze pole-ukazatel ◦ identifikátor pole se chová jako ukazatel na nultý prvek � Pole nelze přiřazovat ani předávat hodnotou ◦ p = a je ekvivalentní p = &a[0] 30 40 p

Řetězce � Každý řetězec musí být vždy ukončen nulou Řetězec - pole znaků (char)

Řetězce � Každý řetězec musí být vždy ukončen nulou Řetězec - pole znaků (char) zakončené nulou ◦ konvence, knihovny "Ahoj" char buffer[4]; strcpy( buffer, "Ahoj"); pozor na uvozovky a apostrofy ! � � � X 'X' "X" 'A' 'h' 'o' 'j' '' = 0 'A' 'h' 'o' 'j' '' vždy myslet na koncovou nulu ! proměnná znaková konstanta - celočíselná hodnota řetězec - ukazatel kód znaku v použitém kódování (ASCII, CP 1250, ISO 8859 -2, EBCDIC, . . . )

Řetězcové proměnné a konstanty Inicializované pole (konstantní ukazatel) ++s 1 nelze! � � .

Řetězcové proměnné a konstanty Inicializované pole (konstantní ukazatel) ++s 1 nelze! � � . . . = { 'U', 'n', 'o', 0 }; char s 1[] = "Uno"; const char *s 2 = "Due"; Inicializovaná proměnná typu ukazatel ++s 2 se přesune na další znak � puts( "Uno"); s 1: 'U' 'n' anonymní globální proměnná const char[] 'o' '' s 2: 'D' 'u' 'e' ekvivalent globální proměnné typu const char[ ] inicializované obsahem konstanty ''

Délka řetězce – různé implementace int strlen ( const char* s) { int i

Délka řetězce – různé implementace int strlen ( const char* s) { int i = 0; while ( s[i] != '') { ++i; } return i; } int i = 0; while ( *s != '') { ++i; ++s; } return i; přístup přes ukazatel více inkrementací prázdné tělo nezapomenout na '; ' !! for( i=0; *s != ''; ++i) ++s; for( i=0; *s != ''; ++i, ++s) ; složitější podmínka: test nenulovosti inkrementace ukazatele int i=0; while ( *s++ != '') ++i; while(a!=0) while(a) podmínka je splněna pokud je nenulová int i=0; while ( *s++) ++i; rozdíl ukazatelů = počet prvků mezi nimi pozor na ± 1 ! char *p = s; while (*p++) ; return p-s-1;

Řetězce – chyby při kopírování vždy pozor na dostatek místa funkce nic nekontroluje !!!

Řetězce – chyby při kopírování vždy pozor na dostatek místa funkce nic nekontroluje !!! � char buf[6]; char pozdrav[] = "Dobry den"; strcpy( buf, pozdrav); buf pozdrav váš program provedl. . . D o b r y d e n kopírování na neinicializovaný ukazatel !!! char *ptr; char pozdrav[] = "Ahoj"; strcpy( ptr, pozdrav); ptr neinicializovaný !!! váš program provedl. . . ptr ? A h o j pozdrav

Vracení řetězců - lokální proměnná string cele_jmeno( const string& jm, const string& prijm) {

Vracení řetězců - lokální proměnná string cele_jmeno( const string& jm, const string& prijm) { return jm + " " + prijm; } char * cele_jmeno( const char * jm, const char * prijm) { char buf[ 100]; strcpy( buf, jm); strcat( buf, " "); strcat( buf, prijm); return buf; } � Naprosto chybné řešení ◦ Nekontroluje přetečení pole buf ◦ Vrací odkaz na lokální proměnnou, která v okamžiku návratu zaniká

Vracení řetězců - statická proměnná char * cele_jmeno( const char * jm, const char

Vracení řetězců - statická proměnná char * cele_jmeno( const char * jm, const char * prijm) { static char buf[ 100]; strcpy( buf, jm); strcat( buf, " "); strcat( buf, prijm); return buf; } � Chybné řešení ◦ Nekontroluje přetečení pole buf ◦ Používá statickou proměnnou �zbytečně zabírá místo i v době, kdy funkce není vyvolána �opakovaná volání ji sdílejí: if ( strcmp( cele_jmeno( j 1, p 1), cele_jmeno( j 2, p 2)) ) �podmínka nikdy nebude splněna, protože strcmp vždy dostane stejné ukazatele na totéž pole buf

Vracení řetězců - parametr void cele_jmeno( char * buf, const char * jm, const

Vracení řetězců - parametr void cele_jmeno( char * buf, const char * jm, const char * prijm) { strcpy( buf, jm); strcat( buf, " "); strcat( buf, prijm); } � Funkční řešení, ale nebezpečné ◦ Nekontroluje přetečení pole buf ◦ Pokud volající nemá spolehlivý horní odhad velikostí jména a příjmení, nemůže tuto funkci bezpečně volat ◦ Většina C knihoven ale funguje podobně void tisk( const char * jm, const char * prijm) { char buf[ 100]; cele_jmeno( buf, jm, prijm); puts( buf); }

Vracení řetězců - bezpečné řešení int cele_jmeno( char * buf, size_t bufsize, const char

Vracení řetězců - bezpečné řešení int cele_jmeno( char * buf, size_t bufsize, const char * jm, const char * prijm) { size_t lj = strlen( jm); size_t lp = strlen( prijm); if ( lj + lp + 2 > bufsize ) { /* error */ return -1; } memcpy( buf, jm, lj); buf[ lj] = ' '; memcpy( buf + lj + 1, prijm, lp); buf[ lj + lp + 1] = 0; return lj + lp + 1; } max velikost pole kontrola korektnosti výsledku kontrola velikosti pole pozor na mezeru a konec! kopírování jednotlivých částí návrat výsledné délky void tisk( const char * jm, const char * prijm) { enum { N = 100 }; char buf[ N]; if( cele_jmeno( buf, N, jm, prijm) > 0) puts( buf); }

Kombinace typových konstrukcí A * x[10] pole ukazatelů A (* x)[10] ukazatel na pole

Kombinace typových konstrukcí A * x[10] pole ukazatelů A (* x)[10] ukazatel na pole A * x() funkce vracející ukazatel A (* x)() ukazatel na funkci A x[10]() pole funkcí - zakázáno A (* x[10])() pole ukazatelů na funkci A x()[10] funkce vracející pole - zakázáno A (* x())[10] funkce vracející ukazatel na pole typicky se nepoužívá pole = ukazatel na 1. prvek čtení deklarací: od identifikátoru doprava, až to nepůjde, tak doleva

Kombinace typových konstrukcí int*(*pf[10])(void); int*(*maso(int*(*p 1)(void), int*(*p 2)(void)))(void); co to je za maso ?

Kombinace typových konstrukcí int*(*pf[10])(void); int*(*maso(int*(*p 1)(void), int*(*p 2)(void)))(void); co to je za maso ? ? ?

Kombinace typových konstrukcí int*(*pf[10])(void); int*(*maso(int*(*p 1)(void), int*(*p 2)(void)))(void); typedef int* fce( void); fce *

Kombinace typových konstrukcí int*(*pf[10])(void); int*(*maso(int*(*p 1)(void), int*(*p 2)(void)))(void); typedef int* fce( void); fce * pf [10]; fce * maso( fce* p 1, fce* p 2); použitím typedef se výrazně zpřehlední kód

OOP v C class A { public: A() : x_(1) {} int f( int

OOP v C class A { public: A() : x_(1) {} int f( int y) { return x_ + y; } private: int x_; }; A* a = new A; a->f(2); explicitní this absence ochrany absence konstruktoru a destruktoru nemožnost přetížení explicitní inicializace typedef struct A_ { int x_; } A; int A_init( A* a) { a->x_ = 1; } int A_f( A* a, int y) { return a->x_ + y; } A* a = malloc( sizeof( A)); A_init(a); A_f(a, 2); explicitní prefix nebo možnost kolize beztypová alokace

Pozdní vazba v C class A { virtual int f(void) { return 1; }

Pozdní vazba v C class A { virtual int f(void) { return 1; } }; class B : public A { virtual int f(void) { return 2; } } A* a = new B; a->f(); virtual method ruční inicializace VMT typedef int fnc(void); typedef struct A_ { fnc* f_; } A; void A_init( A* a, fnc* int A_f( A* a) { return int A_f_body() { return int B_f_body() { return konstruktor inicializace VMT f) { a->f_ = f; } (*a->f_)(); } 1; } 2; } A* a = malloc( sizeof( A)); A_init( a, B_f_body); A_f( a); zavolá se B_f 'odvozená metoda'

Parametry příkazové řádky pole řetězců (ukazatelů na char) C: > myprog. exe -n -w

Parametry příkazové řádky pole řetězců (ukazatelů na char) C: > myprog. exe -n -w a. txt b. txt int main( int argc, char** argv) argv 0 argc 5 a Počet parametrů včetně názvu programu ! = počet ukazatelů v argv . t x t . e - w m y vector<string> arg( argv, argv+argc); b n p r o g x e t

Zpracování příkazové řádky usage: myprog [-n] [-w] file. A file. B int main( int

Zpracování příkazové řádky usage: myprog [-n] [-w] file. A file. B int main( int argc, char** argv) { int n=0, w=0; while( *++argv && **argv=='-') { switch( argv[0][1]) { case 'n': n = 1; break; case 'w': w = 1; break; default: error(); } } if( !argv[0] || !argv[1]) error(); doit( argv[0], argv[1], n, w); return 0; } options nastavení přepínače zbývající parametry 0 b . t x t a . t x t . e x - w výkonná funkce argv - n p r g e

Zpracování příkazové řádky usage: myprog [-n] [-w] [-x 123] [-ffilename] file. A file. B

Zpracování příkazové řádky usage: myprog [-n] [-w] [-x 123] [-ffilename] file. A file. B int main( int argc, char** argv) { int n=0, w=0; int x = 0; char* f = 0; while( *++argv && **argv=='-') { switch( argv[0][1]) { case 'n': n = 1; break; case 'w': w = 1; break; case 'x': x = atoi( *argv+2; break; case 'f': f = *argv+2; break; default: error(); } } if( !argv[0] || !argv[1]) error(); doit( argv[0], argv[1], n, w, x, f); return 0; } číselný parametr řetězcový parametr argv - f f i l . . . - x 1 2 3

Zpracování příkazové řádky int main( int argc, char** argv) { int n=0, w=0; int

Zpracování příkazové řádky int main( int argc, char** argv) { int n=0, w=0; int x = 0; char* f = 0; while( *++argv && **argv=='-') { switch( argv[0][1]) { case 'n': n = 1; break; case 'w': w = 1; break; case 'x': x = atoi( argv[0]+2); break; case 'f': if( argv[0][2]) f = *argv+2; else f = *++argv; break; default: error(); } } if( !argv[0] || !argv[1]) error(); doit( argv[0], argv[1], n, w, x, f); return 0; } argv usage: myprog [-n] [-w] [-x 123] [-f filename] file. A file. B ≡ &(argv[0][2]) -ffile -f file f i l - f - f f e n . . . i . . . l

Variabilní argumenty #include <stdarg. h> typedef va_list ? ? va_start( va_list argptr, last_parm); va_arg(

Variabilní argumenty #include <stdarg. h> typedef va_list ? ? va_start( va_list argptr, last_parm); va_arg( va_list argptr, type); va_end( va_list argptr ); speciální typ inicializace přístup ukončení int sum( int num, . . . ) { int rv = 0; va_list argptr; va_start( argptr, num); for( ; num > 0; num--) { rv += va_arg( argptr, int); } va_end( argptr); return rv; } int answer = sum( 4, 4, 3, 2, 1); typ ! opravdu '. . . ' korektnost parametrů musí zajistit uživatel funkce Náhrada v C++: Variadic Templates

printf int printf( const char * format, . . . ); ◦ ◦ ◦

printf int printf( const char * format, . . . ); ◦ ◦ ◦ ◦ % [flags] [width] [. precision] [opt_pref] type %c - char - znak %d - int - decimálně místo width a/nebo precision znak * hodnota následujícího parametru %x - int - šestnáctkově %ld - long %f - double - s desetinnou tečkou width: min. počet míst na výstupu %g - double - s exponentem precision: max. počet zpracovávaných znaků %s - char * - řetězec #include <stdio. h> printf( "Ahoj %s dnes je %d. ", "Babi", 8, 1); shodu formátu a parametrů musí zajistit programátor neshoda: nedefinované chování fprintf( FILE*, sprintf( char*, swprintf( wchar_t*, _snprintf( char*, int n, _scprintf(. . .

printf(": %c: %6 d: %08 X: %7. 3 f: n", 'a', 17, 1234, -1234.

printf(": %c: %6 d: %08 X: %7. 3 f: n", 'a', 17, 1234, -1234. 5678); : a: ▫▫▫▫ 17: 000004 D 2 : ▫▫-1234. 560: ▫▫-1234. 568: printf(": %s: %6 s: %-6. 3 s: %. 3 s: n", "ahoj", "ahojbabi", "ahoj", "ahoj"); : ahoj: ▫▫ahoj: ahojbabi : ahoj▫▫: aho▫▫▫: aho: printf(": %*d: %-*. *s: n", 6, 17, 6, 3, "ahoj"); : ▫▫▫▫ 17: aho▫▫▫: printf(": %c: %d: %s: n", 0 xffeedd 41, "ahoj", 'a'); : A: : 78263451: ● Unhandled exception at 0 x 0041470 c : Access violation reading location 0 x 00000061

Práce se soubory typ 'soubor' (ukazatel na strukturu) otevření souboru konvence dle OS #include

Práce se soubory typ 'soubor' (ukazatel na strukturu) otevření souboru konvence dle OS #include <stdio. h> FILE* fp; int c; pozor na '\' !!! if( !(fp = fopen("c: \f. txt", "r"))) error(); while( (c = getc( fp)) != EOF) putchar( c); fclose( fp); w: soubor se smaže r: soubor musí existovat mode soubor ex. soubor neex. seek r R Error 0 w Del, W W 0 a W W End r+ R/W Error 0 w+ Del, R/W 0 a+ R/W End a: otevřít na konci konstanta v stdio. h různá od všech možných dat +: vždy čtení i zápis

Textové vs. binární soubory � Textový soubor ◦ ◦ ◦ � konverze konců řádek

Textové vs. binární soubory � Textový soubor ◦ ◦ ◦ � konverze konců řádek ('n') na platformově závislou vnější reprezentaci typicky 0 x 0 D 0 x 0 A (Win) nebo 0 x 0 A (Unix) konverze je automatická, programátor se o to nemusí starat vhodné pro ukládání lidsky čitelných dat getc/putc, fgets/fputs, fprintf, . . . chování fseek/ftell na 'n' nedefinován - nepoužívat Binární soubor ◦ ◦ ◦ žádné konverze se neprovádí v souboru je přesný binární obraz zapisovaných dat vhodné pro ukládání vnitřních datových struktur lidsky přímo nečitelné typicky fread/fwrite, lze i getc/putc (přístup po bajtech) fseek/ftell OK

Funkce pro práci se soubory FILE* fopen( const char* fname, const char* mode); int

Funkce pro práci se soubory FILE* fopen( const char* fname, const char* mode); int fclose( FILE* fp); int fprintf( FILE* fp, const char* format, . . . ); int getc( FILE* fp); int putc( int c, FILE* fp); char* fgets( char* buffer, size_t limit, FILE* fp); int fputs( const char* buffer, FILE* fp); size_t fread( void* ptr, size_t size, size_t n, FILE* fp); size_t fwrite( const void* ptr, size_t size, size_t n, FILE* fp); long ftell( FILE* fp); int fseek( FILE* fp, long offset, int whence); whence: SEEK_SET, SEEK_CUR, SEEK_END int fflush( FILE *fp);

Souborový vs. standardní v/v funkce pro práci se standardním vstupem/výstupem int getchar( void); int

Souborový vs. standardní v/v funkce pro práci se standardním vstupem/výstupem int getchar( void); int putchar( int c); int printf( const char* format, . . . ); char* gets( char* buffer); Nikdy nepoužívat! Nelze ohlídat přetečení bufferu standardní vstup/výstup FILE* stand. otevřený na čtení/zápis před vstupem do main FILE *stdin; FILE *stdout; getchar() getc(stdin) putchar(c) putc(c, stdout) všechny souborové funkce lze použít i pro std. v/v FILE* fp = stdout; if(. . . ) fp = fopen( ". . . ", "r"); c = getc( fp); jednotný zápis na std výstup nebo do souboru

Knihovní funkce C <string. h> <cstring> C++ namespace std strlen, strcmp, stricmp, strcpy, strncpy,

Knihovní funkce C <string. h> <cstring> C++ namespace std strlen, strcmp, stricmp, strcpy, strncpy, strcat, strchr, strstr, memset, memcmp, memcpy, memchr <stdio. h> <cstdio> getchar, putchar, fopen, tmpfile, fclose, getc, putc, fgets, fputs, fread fwrite, ftell, fseek, printf, fprintf, vfprintf, fflush, ungetc FILE, stdin, stdout, EOF, SEEK_SET, . . . <stdlib. h> <cstdlib> malloc, free, atoi, atof, strtol, qsort, rand, exit <ctype. h> <cctype> isalpha, isdigit, isxdigit, isalnum, isspace, ispunct, iscntrl, islower, isupper, tolower, toupper <math. h> <cmath> abs, floor, sin, sqrt, exp, log, . . . <time. h> <ctime> time, gmtime, strftime, asctime, clock, . . . a mnoho dalších <assert. h> <errno. h> <limits. h> <locale. h> <stdarg. h> <setjmp. h>

Pokročilé programování v C++ � přednáška: Bednárek, Yaghob, Zavoral ◦ ◦ ◦ � pokročilá

Pokročilé programování v C++ � přednáška: Bednárek, Yaghob, Zavoral ◦ ◦ ◦ � pokročilá a vybraná témata pokročilá práce se šablonami, generické programování konkurence a paralelismus novinky C++11/14/17/TS externí knihovny, . . . cvičení - samostatná práce ◦ 3 DÚ během semestru ◦ zadání, vypracování, opravení, feedback ◦ body ↠ známka � NPRG 059 - Pokročilé praktikum z objektového programování ◦ ◦ Mgr - povinný pro obor Softwarové systémy doporučený pro SZZ okruhy SW inženýrství a Vývoj software absolvování (Pokročilé C++ && (Pokročilá Java || Pokročilý C#)) + kvalitní sw projekt C++/C#/Java

Interoperabilita � vlastní C moduly ◦ obj, lib, dll/so ◦ jak linkovat C a

Interoperabilita � vlastní C moduly ◦ obj, lib, dll/so ◦ jak linkovat C a C++ moduly ◦ jak dělat společné C/C++ headery � cizí C knihovny ◦ ◦ jak z C++ volat C knihovny callback z C knihoven do C++ mandlování, volací konvence dynamicky linkované knihovny

Překlad více modulů vlastní headery . h . obj . h . cpp knihovny

Překlad více modulů vlastní headery . h . obj . h . cpp knihovny knihovní headery CC . obj kompilace jednoho modulu. obj . c. c. cpp další moduly . obj. lib Link . exe

Vytvoření vlastní knihovny vlastní headery . h knihovní headery . h . cpp CC

Vytvoření vlastní knihovny vlastní headery . h knihovní headery . h . cpp CC . obj kompilace jednoho modulu. obj . c. c. cpp další moduly Lib . lib

C++ exe / C lib zdrojový text / překladač C lib. c CC .

C++ exe / C lib zdrojový text / překladač C lib. c CC . obj Lib . lib CPPC . obj Link . exe lib. h exe. cpp zdrojový text / překladač C++

C++ exe / C lib. c CC . obj Lib . lib Link .

C++ exe / C lib. c CC . obj Lib . lib Link . exe lib. h exe. cpp � CPPC . obj error LNK 2019: unresolved external symbol ◦ "int __cdecl lib_fnc(int)" (? lib_fnc@@YAHH@Z) ◦ referenced in function _main what the. . . hell? ? ?

Mandlování � mangling ◦ mandlování ◦ znetvoření ◦ name-decoration � syntaktická a sémantická informace

Mandlování � mangling ◦ mandlování ◦ znetvoření ◦ name-decoration � syntaktická a sémantická informace o symbolu ◦ ◦ ◦ � int a; int a( void); int a( int, int); class a {}; class a { int a; }; class a { int a( int); }; zjednoznačnění identifikátoru proměnná / funkce / operator / metoda typy a typové konstrukce parametrů a návratové hodnoty třída, další atributy (const, volatile, . . . ) volací konvence formát jednotně nedefinovaný ◦ závislý na platformě, překladači, . . . ◦ obecně nepřenositelné

C++ exe / C lib /* pureclib. h */ /* pureclib. c */ #include

C++ exe / C lib /* pureclib. h */ /* pureclib. c */ #include "pureclib. h" #ifndef PURECLIB__H_ #define PURECLIB__H_ // cppexe. cpp #include "pureclib. h" int lib_x; extern int lib_x; int lib_fnc( int x); int main(. . ) { int i = lib_fnc( 1); } int lib_fnc( int x) { return old_x; } CC _lib_fnc #endif různé překladače různé jazyky různá implementace CPPC ? lib_fnc@@YAHH@Z

Společné hlavičkové soubory /* pureclib. h */ symboly C /* pureclib. c */ #include

Společné hlavičkové soubory /* pureclib. h */ symboly C /* pureclib. c */ #include "pureclib. h" #ifndef PURECLIB__H_ #define PURECLIB__H_ // cppexe. cpp #include "pureclib. h" int lib_x; #ifdef __cplus extern "C" { #endif int main(. . ) { int i = lib_fnc( 1); } int lib_fnc( int x) { return old_x; } extern int lib_x; int lib_fnc( int x); #ifdef } #endif CC _lib_fnc __cplus #endif CPPC - definované CC - nedefinované CPPC _lib_fnc

Volací konvence � způsob implementace volání funkcí ◦ ◦ ◦ � registry vs. zásobník

Volací konvence � způsob implementace volání funkcí ◦ ◦ ◦ � registry vs. zásobník zachovávání registrů pořadí předávání parametrů návratová hodnota příprava a úklid zásobníku konkrétní konvence f( 1, 2); mov eax, 1 mov eax, [ebp+08] mov ebx, 2 mov ebx, [ebp+04] call ? f@@X. . . ◦ není součástí normy - rozšíření �__cdecl - default for C and C++, varargs �__stdcall - Win 32 API functions �__fastcall - arguments in registers, faster �__thiscall - this �__clrcall - C++/CLI, . Net, managed code

C++ callback /* pureclib. h */ #ifdef __cplus extern "C" { #endif int lib_cb(

C++ callback /* pureclib. h */ #ifdef __cplus extern "C" { #endif int lib_cb( int x, int (*cb_fnc)( int)); #ifdef } #endif callback knihovní kód volá klientskou funkci extern "C" určuje i volací konvenci __cplus // cppexe. cpp #include "pureclib. h" /* pureclib. c */ #include "pureclib. h" int lib_cb( int x, int (*cb_fnc)( int)) { return cb_fnc( x); } CC očekává C funkci extern "C" int cpp_fnc( int x) { return x+1; } int main() { lib_cb( i, cpp_fnc); }

Dynamicky linkované knihovny � � použití funkcí dodaných až za běhu není součástí normy

Dynamicky linkované knihovny � � použití funkcí dodaných až za běhu není součástí normy ◦ použití na různých platformách ideově podobné �ale nepřenositelné ◦ pomocí preprocesoru lze multiplatformní rozhraní �ale netriviální � Windows ◦. dll ◦ chová se jako. exe ◦ vlastní zásobník, heap, standardní knihovny � Linux / Unix ◦. so ◦ chová se jako. lib ◦ balíček. o more details: http: //www. symantec. com/connect/articles/ dynamic-linking-linux-and-windows-part-one. . . -part-two

Dynamicky linkované knihovny // dll. cpp // exe_explicit. cpp extern "C" __declspec(dllexport) int add(

Dynamicky linkované knihovny // dll. cpp // exe_explicit. cpp extern "C" __declspec(dllexport) int add( int a, int b) { return a + b; } HINSTANCE dll = Load. Library( TEXT("dll. dll")); if( dll == NULL) return 1; BOOL APIENTRY Dll. Main(. . ) { return TRUE; } typedef int dll_fnc(int, int); dll_fnc* add = (dll_fnc*) Get. Proc. Address( dll, "add"); if( add == NULL) { Free. Library( dll); return 1; } load dll explicit runtime linking běžné volání statické slinkování s dll. lib jen proxy, kód v. dll int result = add(1, 2); Free. Library( dll); // exe_import. cpp extern "C" __declspec(dllimport) int add(int a, int b); int result = add(1, 2);