# Introduction
Les opérateurs permettent de manipuler des données, d'effectuer des calculs, de prendre des décisions. Une maîtrise solide des opérateurs est indispensable pour écrire du code efficace, concis et performant.
---
## 3.1. Opérateur et Opérandes
Commençons par définir les termes clés qui nous accompagneront tout au long de ce chapitre.
> [!definition] Opérateur
> Un **opérateur** est un symbole ou un mot-clé qui représente une action ou une opération spécifique à effectuer sur une ou plusieurs valeurs. En C, les opérateurs sont utilisés pour manipuler des variables et des constantes.
> [!definition] Opérande
> Un **opérande** est la valeur ou la variable sur laquelle un opérateur agit. Selon le nombre d'opérandes qu'il requiert, un opérateur peut être :
> - **Unaire** : agit sur un seul opérande (ex: `-x`, `!condition`).
> - **Binaire** : agit sur deux opérandes (ex: `a + b`, `x == y`).
> - **Ternaire** : agit sur trois opérandes (il n'y en a qu'un en C : l'opérateur conditionnel `? :`).
> [!example] Exemples simples
> - Dans l'expression `a + b`, `+` est l'opérateur et `a` et `b` sont les opérandes.
> - Dans l'expression `-x`, `-` est l'opérateur (unaire) et `x` est l'opérande.
---
## 3.2. Les Opérateurs en C
Le langage C offre un ensemble riche et varié d'opérateurs, classés en différentes catégories selon le type d'opération qu'ils réalisent.
### 3.2.1. Opérateurs Arithmétiques
Ces opérateurs sont utilisés pour effectuer des calculs mathématiques.
| Opérateur | Description | Exemple | Résultat (si `a=10, b=3`) |
| :-------- | :------------------- | :------------- | :------------------------ |
| `+` | Addition | `a + b` | `13` |
| `-` | Soustraction | `a - b` | `7` |
| `*` | Multiplication | `a * b` | `30` |
| `/` | Division | `a / b` | `3` (division entière) |
| `%` | Modulo (reste div.) | `a % b` | `1` |
| `++` | Incrémentation (un.) | `a++` ou `++a` | `a` devient `11` |
| `--` | Décrémentation (un.) | `a--` ou `--a` | `a` devient `9` |
> [!warning] Division entière et modulo
> - Lorsque les deux opérandes de l'opérateur `/` sont des entiers, la division est une **division entière**. Le résultat est la partie entière du quotient. Par exemple, `10 / 3` donne `3`. Pour obtenir une division flottante, au moins un des opérandes doit être un flottant (ex: `10.0 / 3` ou `(double)a / b`).
> - L'opérateur `%` (modulo) ne peut être utilisé qu'avec des opérandes de type entier. Le signe du résultat de `%` est le même que celui du premier opérande (avant C99, c'était dépendant de l'implémentation).
> [!note] Incrémentation et Décrémentation (Préfixe vs Postfixe)
> Les opérateurs `++` et `--` peuvent être utilisés en mode **préfixe** (`++a`) ou **postfixe** (`a++`).
> - **Préfixe** (`++a`, `--a`) : L'opération est effectuée *avant* que la valeur de la variable ne soit utilisée dans l'expression.
> - **Postfixe** (`a++`, `a--`) : L'opération est effectuée *après* que la valeur originale de la variable ait été utilisée dans l'expression.
>
> ```c
> int x = 5;
> int y = ++x; // x devient 6, puis y prend la valeur 6
> // Maintenant, x = 6, y = 6
>
> int a = 5;
> int b = a++; // b prend la valeur 5, puis a devient 6
> // Maintenant, a = 6, b = 5
> ```
>
> > [!warning] Effets de bord multiples
> > Évitez d'utiliser des opérateurs d'incrémentation/décrémentation avec des effets de bord multiples dans une même expression complexe, car l'ordre d'évaluation peut être indéfini et rendre le code imprévisible. Ex: `x = i++ + i++;` est à proscrire.
### 3.2.2. Opérateurs Relationnels
Ces opérateurs sont utilisés pour comparer deux opérandes. Le résultat d'une comparaison est une valeur entière : `1` (vrai) ou `0` (faux).
| Opérateur | Description | Exemple | Résultat (si `a=10, b=3`) |
| :-------- | :-------------------- | :------- | :------------------------ |
| `==` | Égal à | `a == b` | `0` (faux) |
| `!=` | Différent de | `a != b` | `1` (vrai) |
| `>` | Strictement supérieur | `a > b` | `1` (vrai) |
| `<` | Strictement inférieur | `a < b` | `0` (faux) |
| `>=` | Supérieur ou égal | `a >= b` | `1` (vrai) |
| `<=` | Inférieur ou égal | `a <= b` | `0` (faux) |
> [!warning] `==` (égalité) vs `=` (affectation)
> C'est une erreur très courante pour les débutants :
> - `==` est l'opérateur de comparaison d'égalité. Il vérifie si deux valeurs sont égales.
> - `=` est l'opérateur d'affectation. Il assigne la valeur de l'opérande de droite à l'opérande de gauche.
>
> ```c
> int x = 5;
> if (x = 0) { // ATTENTION : ceci est une affectation, pas une comparaison !
> // Le bloc sera exécuté si (x=0) est vrai, c'est-à-dire si 0 est considéré comme vrai.
> // Or, 0 est faux en C. Donc, x sera mis à 0, et la condition sera fausse.
> // Si la valeur affectée était non-nulle, le bloc serait exécuté.
> }
> if (x == 0) { // CORRECT : ceci est une comparaison
> // Le bloc sera exécuté si x est égal à 0.
> }
> ```
### 3.2.3. Opérateurs Logiques
Ces opérateurs sont utilisés pour combiner ou inverser des expressions booléennes (qui sont des entiers en C, où `0` est faux et toute valeur non-nulle est vraie).
| Opérateur | Description | Exemple | Résultat (si `a=10, b=0`) |
| :-------- | :---------- | :------------------- | :------------------------ |
| `&&` | ET logique | `(a > 5) && (b < 1)` | `1` (vrai) |
| <code>\|\|</code> | OU logique | <code>(a < 5) \|\| (b == 0)</code> | `1` (vrai) |
| `!` | NON logique | `!(a == 10)` | `0` (faux) |
> [!note] Évaluation en court-circuit (Short-Circuit Evaluation)
> Les opérateurs `&&` et `||` utilisent une évaluation en court-circuit :
> - Pour `expression1 && expression2` : Si `expression1` est fausse (`0`), `expression2` n'est pas évaluée car le résultat final sera de toute façon faux.
> - Pour `expression1 || expression2` : Si `expression1` est vraie (non-nulle), `expression2` n'est pas évaluée car le résultat final sera de toute façon vrai.
>
> Cette propriété est utile pour éviter des erreurs d'exécution, par exemple, lors de la vérification d'un pointeur avant de le déréférencer :
> ```c
> char *ptr = NULL;
> // ...
> if (ptr != NULL && *ptr == 'A') { // Si ptr est NULL, *ptr ne sera pas évalué
> // ...
> }
> ```
### 3.2.4. Opérateurs Bit à Bit (Bitwise)
Ces opérateurs manipulent les bits individuels des opérandes entiers. Ils sont très utiles pour la programmation de bas niveau, l'optimisation ou la manipulation de flags.
| Opérateur | Description | Exemple | Résultat (si `a=5 (0101_2), b=3 (0011_2)`) |
| :-------- | :-------------------- | :----------- | :----------------------------------------- |
| `&` | ET bit à bit | `a & b` | `1` (`0001_2`) |
| <code>\|</code> | OU bit à bit | <code>a \| b</code> | `7` (`0111_2`) |
| `^` | OU exclusif bit à bit | `a ^ b` | `6` (`0110_2`) |
| `~` | NON bit à bit (un.) | `~a` | `-6` (complément à deux de `0101_2`) |
| `<<` | Décalage à gauche | `a << 1` | `10` (`1010_2`) |
| `>>` | Décalage à droite | `a >> 1` | `2` (`0010_2`) |
> [!example] Manipulation de bits
> ```c
> unsigned char flags = 0b00000101; // Représente 5 en binaire (flag_0 et flag_2 activés)
>
> // Activer un flag (mettre le bit à 1) :
> flags = flags | 0b00000010; // Active flag_1. flags devient 0b00000111 (7)
>
> // Désactiver un flag (mettre le bit à 0) :
> flags = flags & (~0b00000100); // Désactive flag_2. flags devient 0b00000011 (3)
>
> // Tester si un flag est activé :
> if (flags & 0b00000001) { // Teste flag_0
> // flag_0 est activé
> }
>
> // Décalage pour multiplication/division rapide par puissance de 2 :
> int x = 10; // 00001010_2
> x = x << 2; // x devient 40 (00101000_2), équivalent à x * 4
> x = x >> 1; // x devient 20 (00010100_2), équivalent à x / 2
> ```
> [!tip] Utilisation des opérateurs bit à bit
> Les opérateurs bit à bit sont essentiels dans des domaines comme la programmation embarquée, les systèmes d'exploitation, les graphiques ou la robotique, où la manipulation directe des registres matériels ou la gestion efficace de l'espace mémoire est cruciale. Ils permettent de stocker plusieurs informations booléennes (flags) dans un seul octet ou mot.
### 3.2.5. Opérateurs d'Affectation
Ces opérateurs sont utilisés pour assigner une valeur à une variable.
| Opérateur | Description | Exemple | Équivalent | | | |
| :-------- | :------------------------------- | :------------------ | :---------------------- | ---- | ------ | --- |
| `=` | Affectation simple | `x = 5` | `x` prend la valeur `5` | | | |
| `+=` | Affectation avec add. | `x += 2` | `x = x + 2` | | | |
| `-=` | Affectation avec sou. | `x -= 2` | `x = x - 2` | | | |
| `*=` | Affectation avec mul. | `x *= 2` | `x = x * 2` | | | |
| `/=` | Affectation avec div. | `x /= 2` | `x = x / 2` | | | |
| `%=` | Affectation avec mod. | `x %= 2` | `x = x % 2` | | | |
| `&=` | Affectation avec ET | `x &= y` | `x = x & y` | | | |
| ` | =` | Affectation avec OU | `x | = y` | `x = x | y` |
| `^=` | Affectation avec XOR | `x ^= y` | `x = x ^ y` | | | |
| `<<=` | Affectation avec décalage gauche | `x <<= 1` | `x = x << 1` | | | |
| `>>=` | Affectation avec décalage droite | `x >>= 1` | `x = x >> 1` | | | |
> [!note] Chaînage des affectations
> L'opérateur d'affectation `=` est associatif de droite à gauche et renvoie la valeur qui a été affectée. Cela permet de chaîner les affectations :
> ```c
> int a, b, c;
> a = b = c = 10; // c prend 10, puis b prend la valeur de (c=10), puis a prend la valeur de (b=c=10)
> // Au final, a, b et c valent tous 10.
> ```
### 3.2.6. Opérateur Conditionnel (Ternaire)
C'est le seul opérateur ternaire en C. Il fournit un moyen concis d'écrire une instruction `if-else` simple.
| Opérateur | Description | Syntaxe |
| :-------- | :---------------------- | :---------------------------- |
| `? :` | Opérateur conditionnel | `condition ? expr_vrai : expr_faux` |
Si `condition` est vraie (non-nulle), `expr_vrai` est évaluée et son résultat est retourné. Sinon, `expr_faux` est évaluée et son résultat est retourné.
> [!example] Opérateur ternaire
> ```c
> int age = 18;
> char *statut = (age >= 18) ? "Majeur" : "Mineur";
> // statut vaudra "Majeur"
>
> int a = 10, b = 20;
> int max = (a > b) ? a : b; // max vaudra 20
> ```
### 3.2.7. Opérateurs Spéciaux / Divers
Ces opérateurs remplissent des fonctions spécifiques et sont souvent liés à des concepts plus avancés.
| Opérateur | Description | Exemple |
| :-------- | :-------------------------------------------- | :---------------------------------------- |
| `sizeof` | Retourne la taille en octets d'un type ou d'une variable | `sizeof(int)` ou `sizeof(maVariable)` |
| `&` | Opérateur d'adresse (référence) | `&maVariable` (retourne l'adresse mémoire de `maVariable`) |
| `*` | Opérateur de déréférencement (indirection) | `*monPointeur` (accède à la valeur pointée par `monPointeur`) |
| `()` | Appel de fonction, cast de type, groupement d'expressions | `maFonction(arg)`, `(double)entier`, `(a + b) * c` |
| `[]` | Indexation de tableau | `monTableau[0]` |
| `,` | Opérateur virgule (séquence d'évaluation) | `a = (b++, c++)` (b est incrémenté, puis c est incrémenté, puis a prend la valeur finale de c) |
> [!note] `sizeof` et `&` : Préparation aux pointeurs
> Les opérateurs `sizeof` et `&` sont particulièrement importants pour comprendre la gestion de la mémoire et les pointeurs, qui seront abordés dans un prochain chapitre.
> - `sizeof` vous donne des informations sur l'espace mémoire occupé par les données.
> - `&` vous permet d'obtenir l'adresse mémoire d'une variable, ce qui est le fondement des pointeurs.
---
## 3.3. Priorité et Associativité des Opérateurs
Lorsqu'une expression contient plusieurs opérateurs, l'ordre dans lequel ils sont évalués est déterminé par leur **priorité** et leur **associativité**.
> [!definition] Priorité (Precedence)
> La **priorité** d'un opérateur détermine l'ordre d'évaluation des opérateurs dans une expression. Les opérateurs avec une priorité plus élevée sont évalués avant ceux avec une priorité plus basse. Par exemple, la multiplication `*` a une priorité plus élevée que l'addition `+`, donc `2 + 3 * 4` est évalué comme `2 + (3 * 4) = 14`.
> [!definition] Associativité
> L'**associativité** d'un opérateur détermine l'ordre d'évaluation lorsque plusieurs opérateurs de *même priorité* apparaissent dans une expression. Elle peut être de gauche à droite (G-D) ou de droite à gauche (D-G).
> - Dans la majorité des cas, les opérateurs sont évalués de **gauche à droite** (ex: `a / b * c` est `(a / b) * c`).
> - Dans le cas de l'affectation et des opérateurs unaires, les opérateurs sont évalués de **droite à gauche** (ex: `a = b = c` est `a = (b = c)`).
Voici un tableau récapitulatif des opérateurs C par ordre de priorité décroissante.
| Priorité | Opérateurs | Associativité |
| :------- | :--------------------------------------- | :------------ |
| 1 | `()` `[]` `.` `->` `++` (postfixe) `--` (postfixe) | G-D |
| 2 | `++` (préfixe) `--` (préfixe) `!` `~` `+` (unaire) `-` (unaire) `*` (déréférencement) `&` (adresse) `sizeof` (type) `(type)` (cast) | D-G |
| 3 | `*` `/` `%` | G-D |
| 4 | `+` `-` | G-D |
| 5 | `<<` `>>` | G-D |
| 6 | `<` `<=` `>` `>=` | G-D |
| 7 | `==` `!=` | G-D |
| 8 | `&` (bit à bit) | G-D |
| 9 | `^` (bit à bit) | G-D |
| 10 | `|` (bit à bit) | G-D |
| 11 | `&&` | G-D |
| 12 | `||` | G-D |
| 13 | `? :` | D-G |
| 14 | `=` `+=` `-=` `*=` `/=` `%=` `&=` `|=` `^=` `<<=` `>>=` | D-G |
| 15 | `,` | G-D |
> [!tip] Utilisation des parenthèses
> En cas de doute sur la priorité ou l'associativité, ou pour améliorer la lisibilité de votre code, utilisez des parenthèses `()`. Elles forcent l'évaluation de l'expression qu'elles contiennent en premier, quelle que soit la priorité des opérateurs.
>
> ```c
> int result = 5 + 2 * 3; // result vaut 11 (2 * 3 est évalué en premier)
> int result_parentheses = (5 + 2) * 3; // result_parentheses vaut 21 (5 + 2 est évalué en premier)
> ```
> Un code bien parenthésé est souvent plus facile à comprendre et moins sujet aux erreurs.
---
## Conclusion
Nous avons parcouru un large éventail d'opérateurs disponibles en C, des plus courants (arithmétiques, relationnels, logiques) aux plus spécifiques (bit à bit, spéciaux). Vous avez appris à distinguer les opérateurs des opérandes, à comprendre les subtilités de l'incrémentation/décrémentation, et à manipuler les bits. Surtout, la connaissance des priorités et de l'associativité est cruciale pour écrire des expressions C correctes et prévisibles.
Les opérateurs sont les verbes de votre programme C. Les maîtriser vous permet de traduire vos algorithmes en code fonctionnel, d'effectuer des calculs, de prendre des décisions et d'interagir avec les données à un niveau très fin. Cette compréhension est un pilier pour aborder des concepts plus avancés comme les pointeurs, les structures de données et la programmation système ou embarquée, où la manipulation directe de la mémoire et des bits est monnaie courante.
N'hésitez pas à expérimenter avec chaque opérateur et à consulter le tableau de priorité régulièrement. La pratique est la clé de la maîtrise !