David Bednárek Filip Zavoral
Vývoj ◦ první verze C, společný vývoj s UNIXem, jádro v C ◦ 1978Kerninghan, Ritchie: The C Programming Language ◦ 1980AT&T - "C with Classes" ◦ 1983poprvé název C++ (Rick Mascitti) ◦ 1985Stroustrup: The C++ Programming Language ◦ 1998ISO/ANSI norma C++ ◦ 1999ISO/ANSI norma C - 'C99' ◦ 2006C TR1 jen knihovny - traits, wrappers, regexp, numerics,... ◦ 2011C++ 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
... 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
bool struct & enum tags implicitní konverze - enum, void * main - return 0; struct S { int x; }; S s; struct S { int x; }; S s; struct S { int x; }; struct S s; struct S { int x; }; struct S s; typedef struct S_ { int x; } S; S s; typedef struct S_ { int x; } S; S s; bool b = true; typedef enum bool_ { FALSE, TRUE} bool; bool b = TRUE; int b2 = a > 1; typedef enum bool_ { FALSE, TRUE} bool; bool b = TRUE; int b2 = a > 1; _Bool b = TRUE; C99 enum E { NULA }; enum E e = NULA; int x = e; int* p = malloc(sizeof( int)); enum E { NULA }; enum E e = NULA; int x = e; int* p = malloc(sizeof( int)); enum E { NULA }; E e = NULA; int x = (int)e; int* p = (int*)malloc(sizeof(int)); enum E { NULA }; E e = NULA; int x = (int)e; int* p = (int*)malloc(sizeof(int)); int main() {... } int main() {... } int main() {... return 0; } int main() {... return 0; }
Řetězec - pole znaků (char) zakončené nulou ◦ konvence, knihovny "Ahoj" Xproměnná 'X'znaková konstanta - celočíselná hodnota "X"řetězec - ukazatel 'A''h''o''j''\0' Každý řetězec musí být vždy ukončen nulou 'A''h''o''j''\0' vždy myslet na koncovou nulu ! pozor na uvozovky a apostrofy ! char buffer[4]; strcpy( buffer, "Ahoj"); '\0' = 0 kód znaku v použitém kódování (ASCII, CP1250, ISO8859-2, EBCDIC,...) kód znaku v použitém kódování (ASCII, CP1250, ISO8859-2, EBCDIC,...)
static char s1[] = "Uno"; const char *s2 = "Due"; puts( "Uno"); 'U''n''o''\0' 'D''u''e''\0' s1: s2: Inicializovaná proměnná typu ukazatel s2++ se přesune na další znak Inicializovaná proměnná typu ukazatel s2++ se přesune na další znak Inicializované pole (konstantní ukazatel) ++s1 nelze! Inicializované pole (konstantní ukazatel) ++s1 nelze! anonymní globální proměnná const char[] anonymní globální proměnná const char[] ekvivalent globální proměnné typu const char[ ] inicializované obsahem konstanty... = { 'U', 'n', 'o', 0 };
int i = 0; while ( *s != '\0') { ++i; ++s; } return i; int strlen ( const char* s) { int i = 0; while ( s[i] != '\0') { ++i; } return i; } char *p = s; while (*p++) ; return p-s-1; for( i=0; *s != '\0'; ++i) ++s; for( i=0; *s != '\0'; ++i, ++s) ; int i=0; while ( *s++ != '\0') ++i; int i=0; while ( *s++) ++i; přístup přes ukazatel více inkrementací prázdné tělo nezapomenout na ';' !! více inkrementací prázdné tělo nezapomenout na ';' !! složitější podmínka: test nenulovosti inkrementace ukazatele složitější podmínka: test nenulovosti inkrementace ukazatele while(a!=0) while(a) podmínka je splněna pokud je nenulová while(a!=0) while(a) podmínka je splněna pokud je nenulová rozdíl ukazatelů = počet prvků mezi nimi pozor na ± 1 !
Dobryden\0 pozdrav buf char buf[6]; char pozdrav[] = "Dobry den"; strcpy( buf, pozdrav); Dobryden\0 vždy pozor na dostatek místa funkce nic nekontroluje !!! váš program provedl... vždy pozor na dostatek místa funkce nic nekontroluje !!! váš program provedl... char *ptr; char pozdrav[] = "Ahoj"; strcpy( ptr, pozdrav); kopírování na neinicializovaný ukazatel !!! váš program provedl... kopírování na neinicializovaný ukazatel !!! váš program provedl... Ahoj\0 pozdrav ptr ? Ahoj\0 ptr neinicializovaný !!!
Naprosto chybné řešení ◦ Nekontroluje přetečení pole buf ◦ Vrací odkaz na lokální proměnnou, která v okamžiku návratu zaniká char * cele_jmeno( const char * jm, const char * prijm) { char buf[ 100]; strcpy( buf, jm); strcat( buf, " "); strcat( buf, prijm); return buf; } string cele_jmeno( const string& jm, const string& prijm) { return jm + " " + prijm; } string cele_jmeno( const string& jm, const string& prijm) { return jm + " " + prijm; }
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)) )
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); }
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; } 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 kontrola korektnosti výsledku kontrola velikosti pole pozor na mezeru a konec! kontrola velikosti pole pozor na mezeru a konec! kopírování jednotlivých částí návrat výsledné délky
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 čtení deklarací: od identifikátoru doprava, až to nepůjde, tak doleva čtení deklarací: od identifikátoru doprava, až to nepůjde, tak doleva typicky se nepoužívá pole = ukazatel na 1. prvek typicky se nepoužívá pole = ukazatel na 1. prvek
int*(*pf[10])(void); int*(*maso(int*(*p1)(void),int*(*p2)(void)))(void); co to je za maso ???
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
class A { public: A() : x_(1) {} int f( int y) { return x_ + y; } private: int x_; }; A* a = new A; a->f(2); class A { public: A() : x_(1) {} int f( int y) { return x_ + y; } private: int x_; }; A* a = new A; a->f(2); 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); 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í this explicitní prefix nebo možnost kolize nemožnost přetížení beztypová alokace absence ochrany absence konstruktoru a destruktoru absence konstruktoru a destruktoru explicitní inicializace
class A { virtual int f(void) { return 1; } }; class B : public A { virtual int f(void) { return 2; } } A* a = new B; a->f(); class A { virtual int f(void) { return 1; } }; class B : public A { virtual int f(void) { return 2; } } A* a = new B; a->f(); 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); 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); VMT konstruktor inicializace VMT virtual method 'odvozená metoda' zavolá se B_f ruční inicializace
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); 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 '...' speciální typ inicializace přístup ukončení #include typedef va_list ???? va_start( va_list argptr, last_parm); va_arg( va_list argptr, type); va_end( va_list argptr ); #include typedef va_list ???? va_start( va_list argptr, last_parm); va_arg( va_list argptr, type); va_end( va_list argptr ); korektnost parametrů musí zajistit uživatel funkce Náhrada v C++: Variadic Templates typ !
C:\> myprog.exe -n -w a.txt b.txt 0 myprog.exe\0 -n -w a.txt b.txt argv 5 argc int main( int argc, char** argv) pole řetězců (ukazatelů na char) pole řetězců (ukazatelů na char) Počet parametrů včetně názvu programu ! = počet ukazatelů v argv Počet parametrů včetně názvu programu ! = počet ukazatelů v argv vector arg( argv, argv+argc);
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 usage: myprog [-n] [-w] fileA fileB nastavení přepínače zbývající parametry výkonná funkce prg.exe\0 -n -w a.txt b.txt 0 argv
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; } číselný parametr usage: myprog [-n] [-w] [-x123] [-ffilename] fileA fileB řetězcový parametr -x123\0 -ffil... argv
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; } -ffile usage: myprog [-n] [-w] [-x123] [-f filename] fileA fileB -f file -f\0 argv -ffil... filen
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 fprintf( FILE*, sprintf( char*, swprintf( wchar_t*, _snprintf( char*, int n, _scprintf(... místo width a/nebo precision znak * hodnota následujícího parametru 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ů width: min. počet míst na výstupu precision: max. počet zpracovávaných znaků #include printf( "Ahoj %s dnes je %d.%d.", "Babi", 8, 1); #include printf( "Ahoj %s dnes je %d.%d.", "Babi", 8, 1); shodu formátu a parametrů musí zajistit programátor neshoda: nedefinované chování shodu formátu a parametrů musí zajistit programátor neshoda: nedefinované chování
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
#include FILE* fp; int c; if( !(fp = fopen("c:\\f.txt", "r"))) error(); while( (c = getc( fp)) != EOF) putchar( c); fclose( fp); typ 'soubor' (ukazatel na strukturu) typ 'soubor' (ukazatel na strukturu) otevření souboru konvence dle OS otevření souboru konvence dle OS pozor na '\\' !!! konstanta v stdio.h různá od všech možných dat konstanta v stdio.h různá od všech možných dat modesoubor ex.soubor neex.seek rRError0 wDel, WW0 aWWEnd r+R/WR/WError0 w+Del, R/WR/WR/W0 a+R/WR/WR/WR/WEnd +: vždy čtení i zápis a: otevřít na konci r: soubor musí existovat w: soubor se smaže
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
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);
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); jednotný zápis na std výstup nebo do souboru jednotný zápis na std výstup nebo do souboru Nikdy nepoužívat! Nelze ohlídat přetečení bufferu Nikdy nepoužívat! Nelze ohlídat přetečení bufferu všechny souborové funkce lze použít i pro std. v/v všechny souborové funkce lze použít i pro std. v/v
strlen, strcmp, stricmp, strcpy, strncpy, strcat, strchr, strrchr, strstr, memset, memcmp, memcpy, memchr getchar, putchar, fopen, tmpfile, fclose, getc, putc, fgets, fputs, fread fwrite, ftell, fseek, printf, fprintf, vfprintf, fflush, ungetc FILE, stdin, stdout, EOF, SEEK_SET,... malloc, free, atoi, atof, strtol, qsort, rand, exit isalpha, isdigit, isxdigit, isalnum, isspace, ispunct, iscntrl, islower, isupper, tolower, toupper abs, floor, sin, sqrt, exp, exp, log,... time, gmtime, strftime, asctime, clock, a mnoho dalších... a mnoho dalších C++ namespace std
#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++
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
.c.h CC.objLink.exe.obj.lib.obj kompilace jednoho modulu knihovny knihovní headery vlastní headery.cpp.c.cpp další moduly
.c.h CC.objLib.lib.obj kompilace jednoho modulu knihovní headery vlastní headery.cpp.c.cpp další moduly
CPPC.objLink.exe.obj.lib zdrojový text / překladač C exe.cpp lib.c lib.h CCLib zdrojový text / překladač C++
CPPC.objLink.exe.obj.lib exe.cpp lib.c lib.h CC Lib error LNK2019: unresolved external symbol ◦ "int __cdecl lib_fnc(int)" ◦ referenced in function _main what the hell???
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é int a; int a( void); int a( int, int); class a {}; class a { int a; }; class a { int a( int); }; int a; int a( void); int a( int, int); class a {}; class a { int a; }; class a { int a( int); };
/* pureclib.c */ #include "pureclib.h" int lib_x; int lib_fnc( int x) { return old_x; } /* pureclib.c */ #include "pureclib.h" int lib_x; int lib_fnc( int x) { return old_x; } /* pureclib.h */ #ifndef PURECLIB__H_ #define PURECLIB__H_ extern int lib_x; int lib_fnc( int x); #endif /* pureclib.h */ #ifndef PURECLIB__H_ #define PURECLIB__H_ extern int lib_x; int lib_fnc( int x); #endif // cppexe.cpp #include "pureclib.h" int main(....) { int i = lib_fnc( 1); } // cppexe.cpp #include "pureclib.h" int main(....) { int i = lib_fnc( 1); } CPPC CC různé překladače různé jazyky různá implementace různé překladače různé jazyky různá implementace _lib_fnc
/* pureclib.c */ #include "pureclib.h" int lib_x; int lib_fnc( int x) { return old_x; } /* pureclib.c */ #include "pureclib.h" int lib_x; int lib_fnc( int x) { return old_x; } /* pureclib.h */ #ifndef PURECLIB__H_ #define PURECLIB__H_ #ifdef __cplusplus extern "C" { #endif extern int lib_x; int lib_fnc( int x); #ifdef __cplusplus } #endif /* pureclib.h */ #ifndef PURECLIB__H_ #define PURECLIB__H_ #ifdef __cplusplus extern "C" { #endif extern int lib_x; int lib_fnc( int x); #ifdef __cplusplus } #endif // cppexe.cpp #include "pureclib.h" int main(....) { int i = lib_fnc( 1); } // cppexe.cpp #include "pureclib.h" int main(....) { int i = lib_fnc( 1); } CPPC CC symboly C _lib_fnc CPPC - definované CC - nedefinované CPPC - definované CC - nedefinované
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 mov eax, 1 mov ebx, 2 call mov eax, 1 mov ebx, 2 call mov eax, [ebp+08] mov ebx, [ebp+04]... mov eax, [ebp+08] mov ebx, [ebp+04]... f( 1, 2);
/* pureclib.c */ #include "pureclib.h" int lib_cb( int x, int (*cb_fnc)( int)) { return cb_fnc( x); } /* pureclib.c */ #include "pureclib.h" int lib_cb( int x, int (*cb_fnc)( int)) { return cb_fnc( x); } /* pureclib.h */ #ifdef __cplusplus extern "C" { #endif int lib_cb( int x, int (*cb_fnc)( int)); #ifdef __cplusplus } #endif /* pureclib.h */ #ifdef __cplusplus extern "C" { #endif int lib_cb( int x, int (*cb_fnc)( int)); #ifdef __cplusplus } #endif // cppexe.cpp #include "pureclib.h" extern "C" int cpp_fnc( int x) { return x+1; } int main() { lib_cb( i, cpp_fnc); } // cppexe.cpp #include "pureclib.h" extern "C" int cpp_fnc( int x) { return x+1; } int main() { lib_cb( i, cpp_fnc); } CC očekává C funkci extern "C" určuje i volací konvenci callback knihovní kód volá klientskou funkci CC očekává C funkci
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 more details: dynamic-linking-linux-and-windows-part-one...-part-two
// dll.cpp extern "C" __declspec(dllexport) int add( int a, int b) { return a + b; } BOOL APIENTRY DllMain(....) { return TRUE; } // 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; typedefint dll_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); // exe_explicit.cpp HINSTANCE dll = LoadLibrary( TEXT("dll.dll")); if( dll == NULL) return 1; typedefint dll_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); // exe_import.cpp extern "C" __declspec(dllimport) int add(int a, int b); int result = add(1, 2); // exe_import.cpp extern "C" __declspec(dllimport) int add(int a, int b); int result = add(1, 2); explicit runtime linking běžné volání statické slinkování s dll.lib jen proxy, kód v.dll load dll