Cours C 9 Petits secrets du C et programmation avancee
…
Affectations étendues
int main(int argc,char* argv[]) {
int i=0,a[2];
a[0]=a[1]=7;
a[i++]+=2;
printf("i=%d a[0]=%d a[1]=%d\n",i,a[0],a[1]);
i=0; a[0]=7;
a[i++]=a[i++]+2;
printf("i=%d a[0]=%d a[1]=%d\n",i,a[0],a[1]);
return 0;
}
Affectations étendues
+= -= *=
<<= >>=
&= ^= |=
Affectations étendues
int main(int argc,char* argv[]) {
int y+=45;
printf("y=%d\n",y);
return 0;
}
$>gcc -Wall -ansi test.c
test.c: In function `main':
test.c:48: syntax error before '+=' token
test.c:49: `y' undeclared (first use in this function)
test.c:49: (Each undeclared identifier is reported only once
test.c:49: for each function it appears in.)
Labels et sauts
int main(int argc,char* argv[]) {
int d;
/* ... */
if (d==0) goto null_error;
/* ... */
null_error:
/* ... */
return 0;
}
Labels et sauts
$>gcc -Wall -ansi labels.c
labels.c: In function `main':
labels.c:9: parse error before "int"
Labels et sauts
Kernighan & Richie, Le langage C
L'unique exception
Les fonctions imbriquées
$>gcc -Wall -ansi --pedantic-errors nested.c
nested.c: In function `main':
nested.c:9: ISO C forbids nested functions
Le vrai visage de main
char* env[]) { ... }
...
Accéder à une variable
(stdlib.h)
int main(int argc,char* argv[]) { char* login=getenv("USER"); if (login!=NULL) {
printf("Hello %s !\n",login); $>./a.out
Hello paumier !
}
return 0;
}
Invoquer une commande
(stdlib.h)
cmd et attend sa fin complète
int main(int argc,char* argv[]) { printf("exit value=%d\n", system("ls"));
return 0; $>./a.out
f1 dir/
exit value=0
}
Mettre des crochets d'arrêt
void end1() {printf("end 1\n");}
void end2() {printf("end 2\n");}
int main(int argc,char* argv[]) {
atexit(end1);
atexit(end2);
return 0;
} $>./a.out
end 2
end 1
Mettre des crochets d'arrêt
"sauvagement"
void end1() {printf("end 1\n");}
void end2() {printf("end 2\n");} $>./a.out
q
end 2
end 1
$>./a.out
<CTRL+c>
int main(int argc,char* argv[]) {
atexit(end1);
atexit(end2);
fgetc(stdin);
return 0;
}
Allocation sur la pile
Allocation sur la pile
Les règles
Les règles
int main(int argc,char* argv[]) {
/* -h -> help
* -i input
* -o [output] */
char* optstring="hi:o::";
/* ... */
return 0;
}
Les règles
-i xxx ou -ixxx arg = xxx
-i=xxx arg = =xxx
Les règles
Utilisation de getopt
argv[],const char* optstring);
sinon:
– EOF si plus d'option
– en cas d'erreur, cf. transparent prédécent
Utilisation de getopt
int main(int argc,char* argv[]) {
/* -h -> help
* -i input
* -o [output] */
const char* optstring=":hi:o::";
int val;
while (EOF!=(val=getopt(argc,argv,optstring))) {
switch (val) {
case 'h': printf("help\n"); break;
case 'o': printf("output mes\n",optarg); break;
case 'i': printf("input mes\n",optarg); break;
case ':': printf("arg missing for option mec\n",optopt); break;
case '?': printf("unknown option mec\n",optopt); break;
}
}
return 0;
}
Utilisation de getopt
help
arg missing for option i
$>./getopt -o -h -i tutu
output (null)
help
input tutu
$>./getopt -i -y -z -oh
input -y
unknown option z
output h
Utilisation de getopt
int main(int argc,char* argv[]) { const char* optstring=":hi:o::"; int val;
while (EOF!=(val=getopt(argc,argv,
optstring))); $>./a.out aa -h bb -i cc dd
aa
bb
dd
while (optind!=argc) {
printf("gis\n",argv[optind++]);
}
return 0;
}
cc n'y est pas!
Les options longues
const argv[],const char* optstring,
const struct option* longopts,
int *longindex);
Les options longues
struct option {
const char* name;
int has_arg;
int* flag;
int val;
};
1=required_argument,
2=optional_argument
sinon, renvoie 0 et *flag vaut val
val: valeur à renvoyer
Les options longues
courtes
const char* optstring=":hi:o::";
const struct option lopts[] = { {"help", no_argument, NULL, 'h'}, {"input", required_argument, NULL, 'i'}, {"output", optional_argument, NULL, 'o'}, {NULL, no_argument, NULL, 0}
};
Les options longues
*longindex vaut l'indice de l'option dans le tableau
Les options longues
const char* optstring=":hi:o::";
const struct option lopts[] = {
{"help", no_argument, NULL, 'h'}, {"input", required_argument, NULL, 'i'}, {"output", optional_argument, NULL, 'o'}, {NULL, no_argument, NULL, 0}
};
int val,index=-1;
char msg[32];
if (index==-1) sprintf(msg,"short option -%c",val);
else sprintf(msg,"long option --%s",lopts[index].name);
switch (val) {
case 'h': printf("%s\n",msg); break;
case 'o': printf("%s arg=%s\n",msg,optarg); break;
case 'i': printf("%s arg=%s\n",msg,optarg); break;
case ':': printf("argument missing for option %c\n",optopt); break;
case '?': printf("unknown option %c\n",optopt); break;
}
index=-1; /* penser à réinitialiser index! */
}
Les options longues
longues peuvent être abrégées
$>./a.out --help --he --h -h --i=toto --i tutu --output
long option --help
long option --help
long option --help
short option -h
long option --input arg=toto
long option --input arg=tutu
long option --output arg=(null)
Calculs sur les flottants
– mettre des valeurs en cache
– simuler des flottants avec des entiers
Calculs avec cache
#define PI 3.14159265358979323846
void test() {
double x,y,cosinus[360];
int i;
for (i=0;i<360;i++) {
double angle=i*PI/180.0;
cosinus[i]=cos(angle);
}
int before=time(NULL);
x=0;
for (i=0;i<100000000;i++) {
y=cos(i*PI/180.0); x=x+y*y;
}
int middle=time(NULL);
printf("%d seconds\nx=%f\n",middle-before,x);
x=0;
for (i=0;i<100000000;i++) {
y=cosinus[i%360]; x=x+y*y;
}
int end=time(NULL);
printf("%d seconds\nx=%f\n",end-middle,x);
}
$>./a.out
27 seconds
x=50000000.325323
3 seconds
x=49999995.586343 plus rapide, mais légère perte de précision
Un calcul bizarre...
Simuler des flottants
– vitesse
– limite des valeurs
Simuler des flottants
/* A type for manipulating positive floats with 3 decimals */ typedef unsigned int MyFloat;
MyFloat new MyFloat(float f) {
_
if (f1) return -1; return (int)(f*1000);
}
float to_float(MyFloat f) { return f/1000.0; }
MyFloat add(MyFloat a,MyFloat b) { return a+b;
}
MyFloat mult(MyFloat a,MyFloat b) {
return a*b/1000; /* Ne pas oublier la division!! */
}
Simuler des flottants
Simuler des flottants entier sum2 stocké avec plus de précision dans le processeur conversion
Þ perte de précision
Bien allouer
– plein de petits objets (
– plein d'allocations, mais pas de désallocation
Bonne allocation personnelle utilisation d'un tableau
=83540Ko économie
=87572-83540
=4032Ko
≈4Mo
$>./a.out&
$>top
PID USER VIRT RES SHR
19952 paumier 83540 300 252
Bonne allocation personnelle
$>top
PID USER VIRT RES SHR S %CPU %MEM TIME+ COMMAND
21944 paumier 17216 15m 260 T 0.0 1.8 0:00.08 a.out
21999 paumier 9324 300 252 T 0.0 0.0 0:00.01 a.out
Bien réallouer
/* Adds the given value to the given array,
* enlarging it if needed */
void add_int(struct array* a,int value) {
if (a->current==a->capacity) {
a->capacity=a->capacity+1;
a->data=(int*)realloc(a->data,a->capacity*sizeof(int));
if (a->data==HULL) {
fprintf(stderr,"Not enough memory!\n");
exit(1);
}
}
a->data[a->current]=value;
(a->current)++;
}
Bien réallouer
* enlarging it if needed */
void add_int(struct array* a,int value) {
if (a->current==a->capacity) {
a->capacity=a->capacity*2;
a->data=(int*)realloc(a->data,a->capacity*sizeof(int));
if (a->data==HULL) {
fprintf(stderr,"Not enough memory!\n");
exit(1);
}
}
a->data[a->current]=value;
(a->current)++;
}
Bien désallouer
– ne pas le faire
– comptage de référence
– table de pointeurs
– garbage collector
Exemple problématique
Solution 1: éviter le problème
Solution 2: comptage de réf.
Solution 2: comptage de réf.
Solution 3: table de pointeurs
Solution 4: garbage collector