1 / 42

NPRG0 4 1 Programování v C++ Programování v C

NPRG0 4 1 Programování v C++ Programování v C. David Bednárek Filip Zavoral. C vs. C++. V ývoj 1970-3 první verze C , spole č n ý v ý voj s UNIXem , jádro v C 1978 Kerninghan, Ritchie: The C Progr amming Language 1980 AT &T - " C with Classes"

mead
Download Presentation

NPRG0 4 1 Programování v C++ Programování v C

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. NPRG041Programování v C++Programování v C David BednárekFilip Zavoral

  2. C vs. C++ • Vývoj • 1970-3 první verze C, společný vývoj s UNIXem, jádro v C • 1978 Kerninghan, Ritchie:The C Programming Language • 1980AT&T - "C with Classes" • 1983poprvé názevC++ (Rick Mascitti) • 1985Stroustrup: The C++ Programming Language • 1998ISO/ANSI normaC++ • 1999ISO/ANSInorma C - 'C99' • 2006C++ 2003 TR1 • jen knihovny - traits, wrappers, regexp, numerics, ... • 2011 C++ 11 (C++0x) • zásadní rozšíření jazyka - lambda, r-values, generic prog., ... • Proč C v 21. století • jádra OS, drivery, pračky, knihovny, • ú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, exceptions, references, overloading, default arguments, namespaces, new/delete, casting, friend, inline, RTTI, auto, lambda, rvalues, ..., ..., ... • Libraries • containers, iterators & algorithms • strings • streams

  4. Odlišnosti C a C++ • bool • struct & enum tags • implicitní konverze - enum, void * • main - return 0; bool b = true; typedefenumbool_ { 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; typedefstruct 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. Řetězce • Řetězec - pole znaků (char) zakončené nulou • konvence, knihovny "Ahoj" • X proměnná • 'X' znaková konstanta - celočíselná hodnota • "X" řetězec - ukazatel Každý řetězec musí být vždy ukončen nulou '\0' = 0 char buffer[4]; strcpy( buffer, "Ahoj"); pozor na uvozovky a apostrofy ! vždymyslet na koncovou nulu ! kód znaku v použitém kódování (ASCII, CP1250, ISO8859-2, EBCDIC, ...)

  6. Řetězcové proměnné a konstanty • static 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: s2: Inicializovaná proměnná typuukazatel s2++ se přesune na další znak ekvivalent globální proměnné typu const char[ ] inicializované obsahem konstanty

  7. Délkařetězce –různé implementace intstrlen ( const char* s) { inti=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 pozorna ± 1 ! char *p = s; while (*p++) ; return p-s-1; přístup přes ukazatel

  8. Ř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 pozdrav kopírování na neinicializovaný ukazatel !!! váš program provedl... char *ptr; char pozdrav[]= "Ahoj"; strcpy( ptr, pozdrav); ? ptr pozdrav ptr neinicializovaný!!!

  9. 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; }

  10. 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)) )

  11. 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 knihovenale 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); }

  12. 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 pozornamezeru 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

  13. Kombinace typových konstrukcí typicky se nepoužívá pole = ukazatel na 1. prvek čtení deklarací: od identifikátoru doprava, až to nepůjde, tak doleva

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

  15. 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ímtypedefse výrazně zpřehlední kód

  16. OOP v C explicitní this class A { public: A() : x_(1) {} intf( int y) { return x_ + y; } private: int x_; }; A* a = new A; a->f(2); absence ochrany typedefstructA_ { int x_; } A; intA_init( A* a) { a->x_ = 1; } intA_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

  17. 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(); VMT konstruktorinicializace VMT typedefint fnc(void); typedefstruct A_ { fnc* f_; } A; void A_init( A* a, fnc* f) { a->f_ = f; } intA_f( A* a) { return (*a->f_)(); } intA_f_body() { return 1; } intB_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'

  18. Variabilní argumenty typ ! #include <stdarg.h> typedef va_list???? va_start( va_listargptr, last_parm); va_arg( va_listargptr, type); va_end( va_listargptr); speciální typ int sum( int num, ...) { intrv = 0; va_listargptr; 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í korektnostparametrů musí zajistit uživatel funkce Náhrada v C++: Variadic Templates

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

  20. 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 výkonná funkce argv

  21. 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': f = argv[0]+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 argv

  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[0]+2); break; case 'f': if( argv[0][2]) f = argv[0]+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] [-ffilename] fileA fileB -ffile -ffile argv

  23. 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 desetinnouteč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í 

  24. printf :a:▫▫▫▫17:000004D2 :▫▫-1234.560:▫▫-1234.568: :ahoj:▫▫ahoj:ahojbabi :ahoj▫▫:aho▫▫▫:aho: :▫▫▫▫17:aho▫▫▫: :A::78263451:● printf(":%c:%6d:%08X:%7.3f:%7.3f:\n", 'a', 17, 1234, -1234.56, -1234.5678); 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'); Unhandled exception at 0x0041470c :Access violation reading location 0x00000061

  25. Práce se soubory typ 'soubor' (ukazatelnastrukturu) 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); pozorna '\\' !!! a: otevřít na konci konstanta v stdio.h různá od všech možných dat +: vždy čtení i zápis

  26. Textové vs. binární soubory • Textový soubor • konverze konců řádek ('\n') naplatformově 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/ftellna'\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é • typickyfread/fwrite, lzeigetc/putc (přístup po bajtech) • fseek/ftell OK

  27. Funkce pro práci se soubory FILE*fopen( const char* fname, const char* mode); intfclose( FILE* fp); intfprintf( FILE* fp, const char* format, ...); intgetc( FILE* fp); intputc( int c, FILE* fp); char* fgets( char* buffer, size_t limit, FILE* fp); intfputs( const char* buffer, FILE* fp); size_tfread( void* ptr, size_t size, size_t n, FILE* fp); size_tfwrite( 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);

  28. Souborový vs. standardní v/v funkce pro práci se standardním vstupem/výstupem intgetchar( void); intputchar( int c); intprintf(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! Nelzeohlí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

  29. Knihovní funkce C C++ namespacestd <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, ... ... a mnohodalších <assert.h> <errno.h> <limits.h> <locale.h> <stdarg.h> <setjmp.h>

  30. 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++

  31. 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

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

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

  34. 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++

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

  36. Mandlování 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átjednotně nedefinovaný • závislý na platformě, překladači, ... • obecně nepřenositelné

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

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

  39. 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 • 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); moveax, 1 movebx, 2 call ?f@@X moveax, [ebp+08] movebx, [ebp+04] ...

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

  41. 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

  42. 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; typedefintdll_fnc(int, int); dll_fnc* add = (dll_fnc*) GetProcAddress( dll, "add"); if( add == NULL) { FreeLibrary( dll); return 1; } int result = add(1, 2); FreeLibrary( dll); load dll explicit runtime linking běžné volání statické slinkovánís dll.libjen proxy, kód v .dll // exe_import.cpp extern "C" __declspec(dllimport) int add(int a, int b); int result = add(1, 2);

More Related