TD — Séance 1 — Syntaxe C complète (fondamentaux)
Types et conversions, opérateurs, portée, contrôle, fonctions, tableaux et chaînes, comportement indéfini
Prévoir, sans machine, ce que font des fragments de C : valeurs et conversions, état des variables ligne par ligne, trace d’une boucle, pile d’appels, contenu d’un tableau et d’une chaîne dans un dump ; distinguer ce que la norme définit de ce qu’elle laisse indéfini. Pour chaque réponse, nommer la règle appliquée. Machine x86-64 little-endian, Linux, gcc 13, options -std=c17 -Wall -Wextra : char 1 octet (signé), short 2, int et unsigned 4, long et size_t 8. Les fragments sans main sont supposés dans main, avec <stdio.h>, <string.h> et <limits.h> inclus.
Exercice 1 : types et conversions
char note = 'B' + 3;
unsigned char stock = 240;
stock = stock + 30;
short temp = -7;
unsigned int seuil = 5;
int r = temp < seuil;
int part = 7 / 4 * 4;
double moy = (9 + 10 + 12) / 3;
double moy2 = (9 + 10 + 12) / 3.0;
int x = 5;
size_t s = sizeof(x += 10);
printf("%c %d %d %d\n", note, stock, r, part);
printf("%.2f %.2f %d %zu\n", moy, moy2, x, s);- Donner la valeur de
note(code ASCII de'B': 66) et la lettre affichée. - Que vaut
stockaprès la ligne 3 ? Le résultat est-il défini par la norme ? - Ligne 6 : dans quel type la comparaison est-elle faite ? Que vaut
r? Quel avertissement gcc donne-t-il ? - Lignes 7 à 9 : valeurs de
part,moyetmoy2, avec l’ordre des opérations. - Lignes 10 et 11 : valeurs de
xet des. - Écrire les deux lignes affichées.
Exercice 2 : état des variables ligne par ligne
int x = 3;
int y = 7;
int z = 0;
z = x++ * 2 + --y;
x = y > 5 || z++ > 0;
y = x & 2 == 2;
z = z >> 1 ^ 3;
x = (y += 4) - z % 4;- Réécrire chacune des lignes 4 à 8 avec toutes ses parenthèses, selon les priorités.
- Remplir le tableau : valeurs de
x,y,zaprès chaque ligne. - Quelle ligne gcc signale-t-il avec
-Wall, et pourquoi ? Quelle était sans doute l’intention ? - À la ligne 5, quelle opération n’est pas exécutée ? Que vaudrait
zà la fin si elle l’était ?
| ligne | x | y | z |
|---|---|---|---|
début |
3 |
7 |
0 |
4 |
|||
5 |
|||
6 |
|||
7 |
|||
8 |
Exercice 3 : portée et durée de vie
int n = 100;
int f(void)
{
static int n = 3;
n += 2;
return n;
}
int g(void)
{
int n = 50;
n--;
return n;
}
int h(void)
{
n = n / 2;
return n;
}int main(void)
{
int a = f();
int b = f();
printf("%d %d %d\n", a, b, f());
a = g();
b = g();
printf("%d %d\n", a, b);
a = h();
b = h();
printf("%d %d %d\n", a, b, n);
{
int n = 8;
printf("%d\n", n * h());
}
printf("%d\n", n);
return 0;
}- Pour chacune des quatre variables nommées
n(lignes 1, 4, 10 et 32), donner sa portée et sa durée de vie. - Écrire les cinq lignes affichées, en justifiant chaque valeur.
- Dans
h, de quelns’agit-il quandhest appelée depuis le bloc des lignes 31 à 34 ? - Que deviendrait la première ligne affichée si le mot
staticétait retiré de la ligne 4 ?
Exercice 4 : boucles et switch
int total = 0;
int i;
for (i = 1; i <= 12; i += 2) {
if (i % 5 == 0)
continue;
total += i;
if (total > 15)
break;
}
printf("i = %d, total = %d\n", i, total);int t = 20;
int tours = 0;
do {
t -= 7;
tours++;
} while (t > 0);for (int c = 0; c < 5; c++) {
switch (c) {
case 1:
case 3:
printf("i");
break;
case 4:
printf("x");
default:
printf("o");
}
}- Tracer la boucle des lignes 3 à 9 : une rangée par tour (tableau ci-dessous, rangées en trop laissées vides). Qu’affiche la ligne 10 ?
- Combien de tours fait la boucle des lignes 13 à 16, et que vaut
tà la fin ? - Qu’affiche la boucle des lignes 17 à 28 ? Quelles lignes gcc signale-t-il avec
-Wextra?
| tour | i | i % 5 == 0 | total | total > 15 |
|---|---|---|---|---|
1 |
||||
2 |
||||
3 |
||||
4 |
||||
5 |
||||
6 |
Exercice 5 : passage par valeur et récursion
void doubler(int v)
{
v = 2 * v;
}
int triple(int v)
{
return 3 * v;
}
int somme_chiffres(int n)
{
if (n < 10)
return n;
return n % 10 + somme_chiffres(n / 10);
}int p = 8;
doubler(p);
printf("%d\n", p);
p = triple(p);
printf("%d\n", p);
printf("%d\n", somme_chiffres(4705));- Qu’affichent les lignes 17 et 19 ? Expliquer la différence entre
doublerettriple. - Pour
somme_chiffres(4705), remplir le tableau des appels, du premier au dernier :n,n % 10, valeur rendue (rangées en trop laissées vides). - Combien d’appels sont en cours au plus au même moment ? Dans quel ordre les valeurs sont-elles rendues ?
- Que se passerait-il si le test de la ligne 11 était retiré ?
| appel | n | n % 10 | valeur rendue |
|---|---|---|---|
1 |
|||
2 |
|||
3 |
|||
4 |
|||
5 |
Exercice 6 : un tableau et une chaîne dans un dump
int cartons[4] = {35, 150, 23, 290};
char commune[8] = "Nioro";
cartons[2] = cartons[3] - cartons[1];
commune[0] = commune[0] + 32;
commune[3] = '\0';
printf("%s %d %zu %zu\n", commune, cartons[2], strlen(commune), sizeof commune);Dump de la pile relevé avant la ligne 3 (adresses abrégées : 0x00 est l’adresse de cartons). Codes ASCII utiles : N 4e, i 69, o 6f, r 72, n 6e ; une lettre minuscule a le code de la majuscule plus 32 (0x20).
| Addr | +0 | +1 | +2 | +3 | +4 | +5 | +6 | +7 |
|---|---|---|---|---|---|---|---|---|
0x00 |
23 |
00 |
00 |
00 |
96 |
00 |
00 |
00 |
0x08 |
17 |
00 |
00 |
00 |
22 |
01 |
00 |
00 |
0x10 |
4e |
69 |
6f |
72 |
6f |
00 |
00 |
00 |
- Lire les quatre éléments de
cartons(adresse et valeur de chacun). Pourquoicartons[3]occupe-t-il deux octets non nuls ? - À quelle adresse commence
commune? Lire la chaîne ; que valentstrlen(commune)etsizeof communeavant la ligne 3 ? - Remplir le dump après la ligne 5, et entourer les octets modifiés.
- Qu’affiche la ligne 6 ?
| Addr | +0 | +1 | +2 | +3 | +4 | +5 | +6 | +7 |
|---|---|---|---|---|---|---|---|---|
0x00 |
||||||||
0x08 |
||||||||
0x10 |
Exercice 7 (approfondissement) : macros, comportements, édition de liens
A. Macros. Développer à la main, puis donner la valeur affichée :
#define DOUBLE(x) x + x
#define MOITIE(x) ((x) / 2)
printf("%d %d %d\n", 3 * DOUBLE(4), MOITIE(7 + 1), DOUBLE(2) * DOUBLE(2));B. Défini ou indéfini ? Pour chaque fragment, dire si le comportement est défini, défini par l’implémentation, non spécifié ou indéfini, et donner la valeur quand elle existe (gcc, x86-64).
/* (1) */ unsigned char u = 255;
u++;
/* (2) */ int m = INT_MIN;
m = -m;
/* (3) */ int r = -11 % 4;
int q = -11 / 4;
/* (4) */ signed char s = 129;
/* (5) */ int t[3];
t[3] = 1;
/* (6) */ int a = 2;
a = a++ + a;
/* (7) */ int v = f() - g(); /* f et g affichent chacune un message */
/* (8) */ int b = 31;
int k = 1 << b;
unsigned w = 1u << b;C. Édition de liens. Pour chaque cas, les deux fichiers sont compilés ensemble (gcc a.c b.c). Dire si la compilation, puis l’édition de liens, réussissent, et ce qu’affiche le programme le cas échéant.
| cas | a.c |
b.c |
|---|---|---|
| 1 | extern int nb_lots; et main qui affiche nb_lots |
int nb_lots = 64; |
| 2 | le même | static int nb_lots = 64; |
| 3 | int nb_lots = 12; et le même main |
int nb_lots = 64; |
Pour cette séance
Le cours
Les slides
À lire en ligne
À télécharger
- Code de départ du TP (ZIP, 5 Ko)