C++ VSC: Eric Lecolinet - Télécom Paristech WWW - Telecom-Paristech - FR/ Elc
C++ VSC: Eric Lecolinet - Télécom Paristech WWW - Telecom-Paristech - FR/ Elc
C++ VSC: Eric Lecolinet - Télécom Paristech WWW - Telecom-Paristech - FR/ Elc
structures
class nexiste pas en C struct existe
- mais ne contient que des variables dinstance
il ny a :
- pas de mthodes (ni de classe, ni dinstance) - pas de constructeur, ni de destructeur - pas de variables de classe - pas de niveaux daccs : tout est public - pas de rednition des oprateurs loprateur = (affectation) recopie les champs un par un il ne peut tre modi ni interdit (sauf astuces)
allocation/destruction
- pas doprateurs new et delete (ni de constructeur, ni de destructeur) - malloc( ), calloc( ), realloc( ) allouent de la mmoire - free( ) libre la mmoire - sizeof( ) : taille (en octets) - toujours initialiser les pointeurs : un pointeur indni doit valoir NULL
typedef struct { double x, y; } Point; void foo() { Point * p = (Point*) malloc(sizeof(Point)); ..... free(p); p = NULL; .....
Forme contracte:
typedef struct POINT {
double x, y; } Point;
ou encore :
typedef struct {
double x, y; } Point;
encapsulation en C
C
typedef struct { char* name; long id; } User; User* createUser (const char* name, int id); void destroyUser (User*); void setUserName (User*, const char* name); void printUser (const User*); .... void foo() { User* u = createUser("Dupont"); setUserName(u, "Durand"); ..... destroyUser(u); u = NULL;
C++
class User { char* name; // en fait utiliser string long id; public: User (const char* name, int id); virtual ~User( ); virtual void setName(const char* name); virtual void print() const; .... }; void foo() { User* u = new User("Dupont"); u->setName("Durand"); .... delete u; u = NULL;
hritage et polymorphisme
pas dhritage
class Player : public User { .... virtual void print() const; .... };
pas de polymorphisme
User * user = new Player(...); user->print(); // liaison tardive si print() est virtual
pseudo-hritage
typedef struct User { int a; void (*print) (const struct User*); } User; typedef struct Player { User base; int b; } Player; User* newUser() { User* p = (User*) malloc(sizeof(User)); p->a = 0; p->print = printUser; return p; } Player* newPlayer() { Player* p = (Player*) malloc(sizeof(Player)); p->base.a = 0; p->base.print = printPlayer; // cast ncessaire p->b = 0; return p; } int main() { Player* p = newPlayer(); p->base.a = 1; p->b = 2; print(p); } // NB: en fait il faudrait partager les pointeurs de fonctions // de tous les objets dune mme classe via une vtable
// subclass
void print(const User* u) { (u->print)(u); } void printUser(const User *u) { printf("printUser a=%d \n", u->a); } void printPlayer(const Player *u) { printf("printPlayer a=%d b=%d\n", u->base.a, u->b); }
void foo() { oat tab[ ] = {1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}; int indice = ChercheVal(tab, 10, 4.); .... }
scanf() rcupre les adresses des variables i et j de foo() ce qui lui permet de modier leurs valeurs (= ce quelles contiennent en mmoire)
exemple
void swap1(int i, int j) {
int aux;
aux = i; i = j; j = aux; } int main() {
int a = 5, b = 0;
swap1(a, b);
printf(" a = %d, b = %d \n", a, b); } void swap2(int* pi, int* pj) {
int aux;
aux = *pi; *pi = *pj; *pj = aux; } int main() {
int a = 5, b = 0;
swap2(&a, &b);
printf(" a = %d, b = %d \n", a, b); }
exemple
void swap1(int i, int j) {
int aux;
aux = i; i = j; j = aux; } int main() {
int a = 5, b = 0;
swap1(a, b);
printf(" a = %d, b = %d \n", a, b); } a et b inchangs NB: pareil en Java !!! void swap2(int* pi, int* pj) {
int aux;
aux = *pi; *pi = *pj; *pj = aux; } int main() {
int a = 5, b = 0;
swap2(&a, &b);
printf(" a = %d, b = %d \n", a, b); } swap2 change les valeurs de a et b car pi et pj de swap2() pointent sur les variables a et b de foo()
pointeurs et tableaux
tab
// quivaut : p = &tab[0] // valeur du ime lment du tableau // adresse du ime lment du tableau
pointeurs et tableaux
int tab[10]; int* p = tab;
! !
pc = pc + 5; pi = pi + 5;
// 5 caractres plus loin (= 5 octets) // 5 entiers plus loin (= 20 octets si int sur 4 octets)
Larithmtique sur les pointeurs na de sens que : lorsque quils sont typs et de mme type !
attention
les tailles dpendent des machines (et des options de compilation) les int, oat... doivent commencer certaines adresses : (ex: tous les 4 octets pour certains processeur 32 bits)
tableaux bi-dimensionnels
oat mat[5][10] = {{1, 2, 3, 4}, {5, 6}, {7, 8, 9}}; oat truc[][10] = {{1, 2, 3, 4}, {5, 6}, {7, 8, 9}};
initialisation ligne par ligne nombre de lignes ventuellement implicite nombre de colonnes obligatoire et constant : mat[y][x] == *(mat + y*NB_COL + x)
tableaux de tableaux
autre manire de crer des tableaux bi-dimensionnels
char * jours[ ] = {
"Lundi",
"Mardi",
"Mercredi",
"Jeudi",
"Vendredi",
"Samedi",
"Dimanche", };
etc...
jours[ligne][colonne] renvoie le caractre correspondant les lignes ne sont pas ncessairement de mme taille
chanes de caractres
pas de classe string, il faut manipuler les char* une chane de caractres
est une suite de char termine par un 0 (la valeur entire nulle) peut tre dnie de 2 manires : par un tableau :! ! ! ! ! ! ! ! ! char s[ ] = "abcd"; char* p = "abcd"; par un pointeur pointant sur un littral : ! !
chanes de caractres
pas de classe string, il faut manipuler les char* une chane de caractres
est une suite de char termine par un 0 (la valeur entire nulle) peut tre dnie de 2 manires : par un tableau :! ! ! ! ! ! ! ! ! char s[ ] = "abcd"; char* p = "abcd"; par un pointeur pointant sur un littral : ! !
attention
sizeof(s) = 5 : nombre de caractres + 0 nal sizeof(p) = 4 : taille du pointeur (4 si processeur 32 bits) => seul le 0 nal permet de dterminer la taille dans ce cas
Pourquoi ?
Pourquoi ? parce que la mmoire nest pas alloue ou (possiblement) trop petite
plus gnral
char buffer[1000]; if ( fgets( buffer, sizeof(buffer), stdin ) != NULL ) ..... char* fgets(char* str, int num, FILE* stream)
retourne NULL en n de chier ou en cas derreur Note: scanf("%s", s) sarrte au premier espace rencontr, contrairement fgets()
attention la scurit !
#include <stdio.h> #include <stdbool.h> #include <string.h> #define CODE_SECRET "1234" int main(int argc, char**argv) { bool is_valid = false; char code[5]; printf("Enter password: "); scanf("%s", code); if (strcmp(code, CODE_SECRET) == 0) is_valid = true; if (is_valid) printf("Welcome dear customer ;-)\n"); else printf("Invalid password !!!\n"); return 0; }
attention la scurit !
#include <stdio.h> #include <stdbool.h> #include <string.h> #define CODE_SECRET "1234" int main(int argc, char**argv) { bool is_valid = false; char code[5]; printf("Enter password: "); scanf("%s", code); if (strcmp(code, CODE_SECRET) == 0) is_valid = true; if (is_valid) printf("Welcome dear customer ;-)\n"); else printf("Invalid password !!!\n"); printf("Adresses: %p %p %p %p\n", code, &is_valid, &argc, argv); return 0; }
macros
#dene TAILLE 1024
#dene MESSAGE "hello word" #dene MIN(X,Y) ((X) < (Y) ? (X) : (Y)) char tableau[TAILLE]; int i = 1, j = 2; int k = MIN(i, j); // macro paramtre
substitution textuelle par le prprocesseur C avant la compilation les macros permettent (entre-autres) de paramtrer le programme
macros
attention aux effets de bords :
#dene MIN(X,Y) ((X) < (Y) ? (X) : (Y)) int i = 1; int j = 2; int res1 = MAX(i++,j++); int res2 = MAX(++i,++J); // res1 = ? // res2 = ?
enum Jour {LUNDI=1, MARDI, MERCREDI, JEUDI, VENDREDI, SAMEDI, DIMANCHE}; enum Jour j = JEUDI; if (j == SAMEDI) printf("en week end\n");
directives de compilation
#ifndef Person_h #define Person_h #include <string> #include <iostream> #if defined(RAW_POINTERS) # define PTR(TYPE) TYPE* #elif defined(INTRUSIVE_POINTERS) # include "intrusive_ptr.h" # define PTR(TYPE) intrusive_ptr<TYPE> #else # error "Undefined pointer mode" #endif #endif /* Person_h */
rgles
char : caractre (1 octet) int : entier (short <= int <= long) short : entier court (>= 16 bits) bool : boolen (depuis C99, inclure stdbool.h) long : entier long (>= 32 bits) oat : ottant simple prcision double : ottant double prcision long double : encore plus prcis
exemples
ex: Sun 32 bits avec gcc : short = 16 / int = long = 32 / oat = 32 / double = 64 bits voir headers standard limits.h et oat.h (dans: /usr/include sous Unix)
transtypage implicite
conversion implicite vers le type plus grand
Attention : les conversions implicites peuvent tre trompeuses !
int i = 2, j = 4; char c = \n; oat x = 4., y1, y2, y3; i = c; c = i; x = i; i = x; y1 = i + x; y2 = i / x; y3 = i / j;
Que vaut y3 ?
transtypage implicite
conversion implicite vers le type plus grand
Attention : les conversions implicites peuvent tre trompeuses !
int i = 2, j = 4; char c = \n; oat x = 4., y1, y2, y3; i = c; c = i; /* entier tronqu */ x = i; i = x; /* rel tronqu */
y1 = i + x; y2 = i / x; y3 = i / j;
transtypage explicite
conversion explicite au moyen dun cast
int i = 2, j = 4; oat y, z; y = i / j; z = (oat) i / j; // y = 0.0 // Z = 0.5
Attention : ce qui suit na aucun sens ! char * s = 1234; int i = (int) s; // compile mais compltement faux !
manipulation de bits
oprateurs
&! ET |! OU inclusif ^ ! OU exclusif <<! dcalage gauche >> ! dcalage droite ~ ! complment un int n = 0xff, m = 0; m = n & 0x10; m = n << 2; /* quivalent : m = n * 4 */
Attention: ne pas confondre & avec && (et logique) ni | avec | | (ou logique)
compilation spare
plusieurs chiers
- compils indpendamment
.... int main() { char* s = "cos(0.5)"; float res = calc(s); }
main.c
....
calc.c
plusieurs fonctions
- une fonction dnie un chier - est appele dans d'autres chiers
....
Compilation
Edition de liens
excutable
....
compilation spare
plusieurs chiers
- compils indpendamment
.... int main() { char* s = "cos(0.5)"; float res = calc(s); }
main.c
....
calc.c
plusieurs fonctions
- une fonction dnie un chier - est appele dans d'autres chiers
....
Compilation
danger !
- C suppose que la fonction existe - pas de vrication de la signature dans ce cas !
Edition de liens
excutable
compilation spare
trois cas possibles
fonction dnie : dans aucun chier ni librairie => erreur ldition de lien: Symbol not found dans un autre chier avec mme signature => excutable cr et qui fonctionne dans un autre chier avec une autre signature => excutable cr mais plante ou rsultats errons
headers partags
header
- contient dclarations des fonctions dnies dans les .c main.c - inclus la fois dans les chiers : - o les fonctions sont dnies - o les fonctions sont appeles cohrence vrie par transitivit main.o calc.o
#include <stdio.h> #include "calc.h" int main() { char* s = "cos(0.5)"; float res = calc(s); } ....
calc.h
float calc(char* s); ....
calc.c
#include <math.h> #include "calc.h" float calc(char* s) { float res; .... return res; } ....
librairies
binaires contenant cos() printf() etc.
excutable
....
headers partags
header
- contient dclarations des fonctions dnies dans les .c main.c - inclus la fois dans les chiers : - o les fonctions sont dnies - o les fonctions sont appeles aussi pour les fonctions des librairies
#include <stdio.h> #include <math.h>
#include <stdio.h> #include "calc.h" int main() { char* s = "cos(0.5)"; float res = calc(s); } ....
calc.h
float calc(char* s); ....
calc.c
#include <math.h> #include "calc.h" float calc(char* s) { float res; .... return res; } ....
excutable
headers partags
obligatoires en C++
- contrairement C : - la compilation choue si une fonction n'est pas dclare - lditeur de liens vrie la signature des fonctions
librairies dynamiques
- code binaire charg dynamiquement lexcution - .dll (Windows), .so (Linux), dylib (Mac) - avantages : - programmes moins gros et plus rapides (moins de swap si DLL partage) - inconvnient : - ncessite la prsence de la DLL (cf. licences et versions) (cf. variable LD_LIBRARY_PATH (ou quivalent) sous Unix)
mlanger C et C++
meilleure solution
- tout compiler (y compris les .c) avec compilateur C++
mlanger C et C++
dans un header C
- pouvant indiffremment tre inclus dans un .c ou un .ccp, crire :
#ifdef __cplusplus extern "C" { #endif void foo(int i, char c, float x); int goo(char* s, char const* s2);