Cheatsheet C
Variables et Types de Données
En programmation de microcontrôleurs, la sélection efficace du type de données est cruciale pour optimiser l'utilisation de la mémoire et la performance.
Types de Base
- int : Un entier. La taille dépend de l'architecture (souvent 16 ou 32 bits sur les microcontrôleurs).
- char : Un caractère ou un petit entier (8 bits).
- float : Nombre à virgule flottante. L'utilisation est généralement déconseillée sur des microcontrôleurs sans unité de calcul en virgule flottante (FPU).
- double : Nombre à virgule flottante double précision. Évitez son utilisation sur les microcontrôleurs pour économiser de l'espace mémoire.
Types Modifiés
- unsigned : Utilisé avec
int
,char
, etc., pour indiquer des valeurs toujours positives. - short / long : Modifie la taille d'un
int
. - volatile : Indique que la valeur de la variable peut changer à tout moment, utile pour la lecture de registres de périphériques.
Types Fixes (stdint.h
)
INFO
Pour garantir la portabilité entre différents microcontrôleurs, il est recommandé d'utiliser des types à taille fixe définis dans stdint.h
- uint8_t, uint16_t, uint32_t, uint64_t : Entiers non signés de 8, 16, 32, et 64 bits.
- int8_t, int16_t, int32_t, int64_t : Entiers signés de 8, 16, 32, et 64 bits.
Utilisation de la Mémoire
- register : Suggère au compilateur de stocker la variable dans un registre du processeur pour un accès rapide.
- static : Maintient la variable en vie pendant toute l'exécution du programme, en conservant sa valeur entre les appels.
- const : Indique que la valeur de la variable ne changera pas, ce qui peut aider le compilateur à optimiser le code.
Pointeurs
Les pointeurs sont largement utilisés en programmation de microcontrôleurs pour accéder aux registres matériels et pour la gestion efficace de la mémoire :
- Déclaration :
type *nom;
oùtype
est le type de données pointé. - Utilisation : Accès direct aux adresses mémoire, manipulation de tableaux, et passage efficace d'arguments aux fonctions.
Tableaux
En C, un tableau correspond à une collection ordonnée d'éléments, tous du même type, stockés de manière contiguë en mémoire. Chaque élément du tableau peut être directement accédé à l'aide d'un index. Les tableaux en C sont utilisés pour stocker des données de manière structurée, permettant de les manipuler efficacement à travers des indices plutôt que de gérer chaque élément individuellement
Déclaration
- Syntaxe de base :
type nom[size];
type
: le type de données de chaque élément du tableau (ex :int
,float
,char
).nom
: le nom du tableau.size
: le nombre d'éléments que le tableau peut contenir.
Exemple :
int myArray[10];
Initialisation
Initialisation avec des valeurs spécifiques :
cint myArray[5] = {1, 2, 3, 4, 5};
Initialisation automatique à zéro :
cint myArray[5] = {0};
Initialisation sans spécifier la taille :
cint myArray[] = {1, 2, 3, 4, 5};
Accès aux Éléments
- Accéder à un élément :
nom[index]
index
: l'indice de l'élément auquel accéder, commençant à 0.
Exemple :
int value = myArray[2]; // Accède au 3ème élément du tableau
Parcourir un Tableau
- Utilisation d'une boucle
for
:cfor(int i = 0; i < 5; i++) { printf("%d\n", myArray[i]); }
Tableaux Multidimensionnels
- Déclaration :
type nom[size1][size2];
- Permet de créer des tableaux à plusieurs dimensions, comme des matrices.
Exemple :
int matrix[3][4]; // Tableau de 3 lignes et 4 colonnes
- Accès aux éléments :c
matrix[0][1] = 10; // Accède à l'élément de la première ligne, deuxième colonne
Passer un Tableau à une Fonction
- Les tableaux sont passés par référence aux fonctions.
- Il faut spécifier le type d'élément et la taille lors de la déclaration du paramètre (ou omettre la taille pour les tableaux unidimensionnels).
Exemple :
void printArray(int arr[], int size) {
for(int i = 0; i < size; i++) {
printf("%d\n", arr[i]);
}
}
Important à Savoir
- En C, la taille d'un tableau doit être connue au moment de la compilation ou doit être allouée dynamiquement en utilisant
malloc
ou des fonctions similaires pour une allocation dynamique. - L'indice des éléments d'un tableau commence toujours par 0.
- Accéder à un indice hors limites du tableau est une erreur de programmation qui peut conduire à des comportements inattendus.
Bien sûr ! Voici un tutoriel rapide sur les énumérations (enum) en C :
Enumération
Les énumérations en C permettent de définir un ensemble de valeurs nommées, ce qui rend le code plus lisible, plus compréhensible et moins sujet aux erreurs.
Définition
Une énumération est définie à l'aide du mot-clé enum
, suivi du nom de l'énumération et de la liste des valeurs séparées par des virgules entre des accolades. Par exemple :
enum JoursSemaine {
Lundi,
Mardi,
Mercredi,
Jeudi,
Vendredi,
Samedi,
Dimanche
};
Utilisation
Une fois que vous avez défini une énumération, vous pouvez l'utiliser pour déclarer des variables dont les valeurs peuvent être l'une des valeurs définies dans l'énumération. Par exemple :
enum JoursSemaine jourCourant;
jourCourant = Lundi;
Attribution de valeurs
Vous pouvez également attribuer des valeurs spécifiques à chaque élément de l'énumération. Par exemple :
enum Couleurs {
Rouge = 1,
Vert = 2,
Bleu = 4,
Jaune = 8
};
Utilisation dans les instructions switch
Les énumérations sont souvent utilisées dans les instructions switch
pour rendre le code plus lisible et plus compréhensible. Par exemple :
switch (jourCourant) {
case Lundi:
printf("C'est lundi !\n");
break;
case Mardi:
printf("C'est mardi !\n");
break;
// Autres jours de la semaine...
}
Structures
Les structures sont des types de données utilisateur qui permettent de regrouper des variables de différents types sous un même nom, ce qui est particulièrement utile pour organiser des données complexes dans vos programmes.
Définition
Pour définir une structure, utilisez le mot-clé struct
suivi d'un nom de structure et d'un bloc définissant les champs de la structure.
struct NomStructure {
type champ1;
type champ2;
...
};
Déclaration
Après avoir défini une structure, vous pouvez créer des variables de ce type :
struct NomStructure variable1, variable2;
Initialisation
Vous pouvez initialiser une structure au moment de la déclaration en listant les valeurs de ses champs entre accolades :
struct NomStructure variable = {valeur1, valeur2, ...};
Accès aux Membres
Pour accéder à un champ spécifique d'une structure, utilisez l'opérateur point (.
) :
variable.champ1 = valeur; // Affectation
Pointeurs vers des Structures
Lorsque vous avez un pointeur vers une structure, utilisez l'opérateur flèche (->
) pour accéder à ses champs :
struct NomStructure *ptr = &variable;
ptr->champ1 = valeur; // Affectation via pointeur
Structures Anonymes
Il est possible de définir des structures sans nommer le type, pour une utilisation immédiate :
struct {
type champ1;
type champ2;
} variable;
Typedef et Structures
Vous pouvez utiliser typedef
pour définir un alias pour un type de structure, simplifiant ainsi la déclaration de variables de ce type :
typedef struct {
type champ1;
type champ2;
} AliasStructure;
AliasStructure variable;
Tableaux de Structures
Vous pouvez créer des tableaux de structures pour stocker plusieurs éléments du même type structuré :
struct NomStructure tableau[10];
Opérateurs Ternaires
L'opérateur ternaire, également connu sous le nom d'opérateur conditionnel, est un raccourci pour les instructions if-else
en C. Il est composé de trois expressions séparées par des points d'interrogation ? et des deux-points :.
Syntaxe :
(expression1) ? (expression2) : (expression3);
expression1
est une condition. Si cette condition est vraie,expression2
est exécutée, sinonexpression3
est exécutée.
Exemple Complet
#include <stdio.h>
int main() {
int num = 10;
(num % 2 == 0) ? printf("%d est pair.\n", num) : printf("%d est impair.\n", num);
return 0;
}
Fonctions
En programmation, les fonctions offrent plusieurs avantages clés, notamment la modularité, la réutilisabilité et la facilité de maintenance du code. En encapsulant des blocs de code dans des fonctions, les développeurs peuvent diviser un programme complexe en sous-routines plus simples et plus gérables, rendant le code plus lisible et plus facile à comprendre. Cela permet également de réutiliser le même bloc de code à différents endroits sans avoir à le réécrire, favorisant ainsi l'efficacité et réduisant les risques d'erreur.
Déclaration
La déclaration (ou prototype) d'une fonction informe le compilateur sur le type de retour de la fonction, son nom, et les types de ses paramètres.
- Syntaxe :
type_retour nom_fonction(type_param1 nom_param1, type_param2 nom_param2, ...);
type_retour
est le type de donnée que la fonction va retourner.nom_fonction
est le nom de la fonction.- Les paramètres
(type_param1 nom_param1, ...)
sont les entrées de la fonction. Les fonctions peuvent également être déclarées sans paramètres.
Définition
La définition d'une fonction comprend le corps de la fonction, où le code à exécuter est écrit.
- Syntaxe :c
type_retour nom_fonction(type_param1 nom_param1, type_param2 nom_param2, ...) { // Corps de la fonction return valeur; // correspondant au type_retour }
Appel d'une Fonction
Pour exécuter une fonction, vous devez l'appeler depuis un autre endroit de votre programme.
- Syntaxe :
nom_fonction(valeur_param1, valeur_param2, ...);
Exemple Complet
#include <stdio.h>
// Déclaration de fonction
int somme(int a, int b);
int main() {
int resultat = somme(5, 3); // Appel de fonction
printf("La somme est : %d\n", resultat);
return 0;
}
// Définition de fonction
int somme(int a, int b) {
return a + b;
}
Points Importants
- Type de Retour : Si une fonction ne doit rien retourner, utilisez
void
comme type de retour. - Paramètres :
- Les paramètres passés à une fonction sont par défaut passés par valeur. Cela signifie que la fonction travaille avec une copie des valeurs, et non avec les variables elles-mêmes.
- Pour modifier les valeurs des variables passées, utilisez les pointeurs comme paramètres de la fonction.
- Portée des Variables :
- Les variables définies dans une fonction (y compris les paramètres) sont locales à cette fonction.
- Les variables globales, déclarées en dehors de toute fonction, sont accessibles de n'importe où dans le fichier.
Bonnes Pratiques
- Nommer Clairement : Choisissez des noms de fonctions qui décrivent clairement ce qu'elles font.
- Diviser pour Régner : Divisez votre code en fonctions pour résoudre des sous-problèmes spécifiques. Cela rend le code plus lisible et réutilisable.
- Commenter : Commentez les fonctions pour expliquer ce qu'elles font, quels sont leurs paramètres, et ce qu'elles retournent.