Prezentace se nahrává, počkejte prosím

Prezentace se nahrává, počkejte prosím

NPRG041 Programování v C++ Programování v C

Podobné prezentace


Prezentace na téma: "NPRG041 Programování v C++ Programování v C"— Transkript prezentace:

1 NPRG041 Programování v C++ Programování v C
David Bednárek Filip Zavoral

2 C vs. C++ Vývoj Proč C v 21. století
první verze C, společný vývoj s UNIXem, jádro v C 1978 Kerninghan, Ritchie: The C Programming Language 1983 Rick Mascitti: poprvé název C++ 1985 Stroustrup: The C++ Programming Language 1998 ISO/ANSI norma C++ 1999 ISO/ANSI norma C - 'C99' 2011+ 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

3 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

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

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

6 Pole a ukazatele, aritmetika ukazatelů
5 ? 20 30 40 p = &a[1]; *(p+3) = 40; Operátor [] p[i]  *(p+i) &p[i]  p+i 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] přičtení čísla k ukazateli  posun o n prvků p indexování pole (ukazatele) je 'jen' jiný zápis přístupu přes ukazatel identifikátor pole je ukazatel na svůj nultý prvek

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

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

9 Délka řetězce – různé implementace
int strlen ( const char* s) { int i = 0; while ( s[i] != '\0') { ++i; } return i; více inkrementací prázdné tělo nezapomenout na ';' !! for( i=0; *s != '\0'; ++i) ++s; for( i=0; *s != '\0'; ++i, ++s) ; složitější podmínka: test nenulovosti inkrementace ukazatele int i=0; while ( *s++ != '\0') ++i; int i = 0; while ( *s != '\0') { ++i; ++s; } return 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; přístup přes ukazatel

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

11 Vracení řetězců - lokální proměnná
Naprosto chybné řešení Nekontroluje přetečení pole buf Vrací odkaz na lokální proměnnou, která v okamžiku návratu zaniká 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; }

12 Vracení řetězců - statická proměnná
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í: podmínka nikdy nebude splněna, protože strcmp vždy dostane stejné ukazatele na totéž pole buf char * cele_jmeno( const char * jm, const char * prijm) { static char buf[ 100]; strcpy( buf, jm); strcat( buf, " "); strcat( buf, prijm); return buf; } if ( strcmp( cele_jmeno( j1, p1), cele_jmeno( j2, p2)) )

13 Vracení řetězců - parametr
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 cele_jmeno( char * buf, const char * jm, const char * prijm) { strcpy( buf, jm); strcat( buf, " "); strcat( buf, prijm); } void tisk( const char * jm, const char * prijm) { char buf[ 100]; cele_jmeno( buf, jm, prijm); puts( buf); }

14 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; } 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); } max velikost pole kontrola korektnosti výsledku

15 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

16 Kombinace typových konstrukcí
int*(*pf[10])(void); int*(*maso(int*(*p1)(void),int*(*p2)(void)))(void); co to je za maso ???

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

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

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

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

21 Zpracování příkazové řádky
usage: myprog [-n] [-w] fileA fileB 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 b . t x \0 a . t x \0 - w \0 výkonná funkce - n \0 argv p r g . e x \0

22 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+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; usage: myprog [-n] [-w] [-x123] [-ffilename] fileA fileB číselný parametr řetězcový parametr - f i l ... - x 1 2 3 \0 argv

23 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; usage: myprog [-n] [-w] [-x123] [-f filename] fileA fileB ≡ &(argv[0][2]) -ffile -f file f i l e n ... - f \0 - f i l ... argv

24 Variabilní argumenty typ ! speciální typ opravdu '...' inicializace
#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 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); opravdu '...' inicializace přístup ukončení korektnost parametrů musí zajistit uživatel funkce Náhrada v C++: Variadic Templates

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

26 printf printf(":%c:%6d:%08X:%7.3f:%7.3f:\n", 'a', 17, 1234, , ); printf(":%s:%6s:%6s:%-6s:%-6.3s:%.3s:\n", "ahoj", "ahoj", "ahojbabi", "ahoj", "ahoj", "ahoj"); printf(":%*d:%-*.*s:\n", 6, 17, 6, 3, "ahoj"); printf(":%c:%c:%d:%s:\n", 0xffeedd41, "ahoj", "ahoj", 'a'); :a:▫▫▫▫17:000004D2 :▫▫ :▫▫ : :ahoj:▫▫ahoj:ahojbabi :ahoj▫▫:aho▫▫▫:aho: :▫▫▫▫17:aho▫▫▫: :A:: :● Unhandled exception at 0x c : Access violation reading location 0x

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

28 Textové vs. binární soubory
Textový soubor konverze konců řádek ('\n') na platformově závislou vnější reprezentaci typicky 0x0D 0x0A (Win) nebo 0x0A (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

29 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);

30 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); 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) FILE* fp = stdout; if( ...) fp = fopen( "...", "r"); c = getc( fp); Nikdy nepoužívat! Nelze ohlídat přetečení bufferu všechny souborové funkce lze použít i pro std. v/v jednotný zápis na std výstup nebo do souboru

31 Knihovní funkce C <string.h> <cstring>
C++ namespace std <string.h> <cstring> strlen, strcmp, stricmp, strcpy, strncpy, strcat, strchr, strrchr, 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, exp, log, ... <time.h> <ctime> time, gmtime, strftime, asctime, clock, ... pro priste udelat obrazek na fread/fwrite ... a mnoho dalších <assert.h> <errno.h> <limits.h> <locale.h> <stdarg.h> <setjmp.h>

32 Co (a proč ) dělá tento program?
#define _ F-->00||F-OO--; int F=00,OO=00;main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO() { _-_-_-_ _-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_ } Je v C, nikoliv v C++

33 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 NPRG059 - 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

34 Interoperabilita vlastní C moduly cizí C knihovny 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

35 kompilace jednoho modulu
Překlad více modulů vlastní headery knihovní headery knihovny .h .h .obj .obj .obj .obj .obj .lib .cpp CC .obj Link .exe Tohle obecne znaji - strucne!! kompilace jednoho modulu .obj .obj .c .obj .c .cpp další moduly

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

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

38 C++ exe / C lib error LNK2019: unresolved external symbol
lib.c CC .obj Lib .lib lib.h exe.cpp CPPC .obj Link .exe error LNK2019: unresolved external symbol "int __cdecl lib_fnc(int)" referenced in function _main what the hell???

39 Mandlování mangling 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); }; mangling mandlování znetvoření name-decoration syntaktická a sémantická informace o symbolu 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é

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

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

42 Volací konvence způsob implementace volání funkcí konkrétní konvence
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 není součástí normy - rozšíření __cdecl - default for C and C++, varargs __stdcall - Win32 API functions __fastcall - arguments in registers, faster __thiscall - this __clrcall - C++/CLI, .Net, managed code f( 1, 2); mov eax, 1 mov ebx, 2 call mov eax, [ebp+08] mov ebx, [ebp+04] ...

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

44 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: dynamic-linking-linux-and-windows-part-one ...-part-two

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


Stáhnout ppt "NPRG041 Programování v C++ Programování v C"

Podobné prezentace


Reklamy Google