Skip to content

Latest commit

 

History

History
294 lines (251 loc) · 9.24 KB

contributing.md

File metadata and controls

294 lines (251 loc) · 9.24 KB

👨‍💻 Contribution au Projet PaxOS-9

Chaque nouvelle Pull Request (PR) doit adhérer aux règles suivantes pour être acceptée :

  • Conventions de Codage : Respectez les conventions de codage énoncées ci-dessous.

  • Absence de Warnings : Assurez-vous que le code ajouté ne génère pas de warnings lors de la compilation. Traitez tout avertissement émis par le compilateur avant de soumettre la PR.

❓ Pourquoi des bonnes pratiques de codage en C++ ?

Le langage C++ est reconnu pour sa richesse et sa puissance, mais cette complexité peut parfois rendre la collaboration difficile. L'utilisation de bonnes pratiques de codage en C++ offre de nombreux avantages, notamment :

  • Cohérence : en adoptant des conventions de codage cohérentes, nous facilitons la lecture du code pour l'ensemble de l'équipe de développement.

  • Maintenabilité : des pratiques de codage bien établies rendent le code plus facile à comprendre, à maintenir et à améliorer au fil du temps.

  • Sécurité : en suivant des bonnes pratiques, nous contribuons à la réduction des erreurs et des vulnérabilités potentielles dans notre code.

  • Performance : Certaines approches de codage peuvent influencer de manière favorable les performances du programme final. Il est essentiel de garder à l'esprit que le code sera exécuté sur un ESP32.

Nommage des variables

  • Nommer les variables de manière explicite et :
  • utilisez pMaVariable pour indiquer que c'est un pointeur.
  • utilisez sMaVariableStatique pour indiquer que c'est une variable statique.
  • utilisez spMonPointeurStatique pour indiquer que c'est un pointeur statique.
int* pMaVariable;
static sMaVariableStatique = 42;
static int* spMonPointeurStatique;

Classes

  • Commencez le nom des classes par un "C" majuscule.
  • Commencez le nom de la variable par un m_ pour indiquer que cette variable est membre.
  • ⚠️ N'oubliez pas : par défaut dans une classe, tout est en privé.
class CApp {
private:
    int m_id = 0;
    int* m_pId;
    static int m_sCount = 42;
    static int* m_spData;
};

Polymorphisme

⚠️ Ne pas oublier les destructeurs virtuels

  • Assurez-vous de déclarer le destructeur de la classe de base comme virtuel si vous prévoyez d'utiliser l'héritage polymorphique.
class CBase {
public:
    virtual ~CBase() = default;
};

class CDerived : public CBase {
public:
    ~CDerived() override { /* Destructeur de la classe dérivée */ }
};

Utilisation prudente des Casts

  • Privilégiez les Casts C++ : Utilisez les casts C++ (static_cast et dynamic_cast) plutôt que les anciens style casts (C-style casts). Les casts C++ fournissent une sémantique plus claire et permettent une vérification de type plus robuste.

Casts Entre Types Similaires

✅ Utilisez static_cast pour des conversions simples entre types compatibles.

// Utilisation de static_cast pour des conversions simples
float floatValue = static_cast<float>(intValue);

✅ Casts de Sécurité avec dynamic_cast

  • Utilisez dynamic_cast pour effectuer des casts dynamiques, principalement dans le contexte de la programmation orientée objet avec héritage polymorphique.
class CBase {
    // ...
};

class CDerived : public CBase {
    // ...
};

CBase* pBasePtr = new CDerived;
CDerived* pDerivedPtr = dynamic_cast<CDerived*>(pBasePtr);

⚠️ Évitez les C-Style Casts

  • Évitez l'utilisation des anciens style casts ((type)value). Les casts C++ offrent une meilleure expressivité et une sécurité accrue.
// Évitez l'utilisation des anciens style casts
float floatValue = (float)intValue;  // À éviter

⚠️ Évitez reinterpret_cast dans la mesure du possible

  • Limitez l'utilisation de reinterpret_cast aux situations où une conversion entre types pointeurs ou entre pointeur et entier est absolument nécessaire. Cela peut introduire des comportements indéfinis et doit être utilisé avec prudence.
// Évitez autant que possible l'utilisation de reinterpret_cast
int* pValue = reinterpret_cast<int*>(pSomeVoidPointer);

⚠️ Évitez const_cast

  • Évitez autant que possible l'utilisation de const_cast. Cherchez des alternatives pour éviter des modifications non intentionnelles de la constance.
// Évitez autant que possible l'utilisation de const_cast
const int constValue = 42;
int& nonConstRef = const_cast<int&>(constValue);  // À éviter 

Structures

  • Commencez le nom des structures par un "S" majuscule.
  • Utilisez les structures uniquement si elles ne contiennent pas de méthodes.
  • ⚠️ N'oubliez pas : par défaut dans une structure, tout est en publique.

Enumérations

  • Commencez le nom des énumérations par un "E" une majuscule.
enum EColor {
    Red,
    Green,
    Blue
};

Utilisation de pointeurs

  • Évitez les raw pointers :
  • Utilisez des smart pointers plutôt que des raw pointers, sauf dans des cas extrêmes.
#include <memory>

std::unique_ptr<int> myUniquePtr = std::make_unique<int>(42);
std::shared_ptr<int> mySharedPtr = std::make_shared<int>(42);

Utiliser les références à la place des pointeurs quand c'est possible

Lorsque vous avez la possibilité de choisir entre les références et les pointeurs, optez pour les références. Les références offrent une syntaxe plus claire et réduisent le risque d'erreurs liées à la gestion de la mémoire.

#include <iostream>
#include <string>

// Fonction utilisant une référence
void displayName(const std::string& value) {
    std::cout << "Hello world, " << value << " !" << std::endl;
}

int main() {
    // Variable entière
    std::string name = "Paxo-OS 8";

    // Appel de la fonction en passant la variable par référence
    displayName(name);

    return 0;
}

Constness

  • Utilisez le mot-clé const pour déclarer des variables qui ne doivent pas être modifiées après leur initialisation.
const int constantValue = 42;
  • Utilisez const pour indiquer si une méthode modifie ou non l'état de l'objet. Les méthodes const ne modifient pas l'état de l'objet et devraient être marquées comme telles.
class CMyClass {
public:
    int getValue() const        // Méthode constante
    {
        return m_id;
    }
    void setValue(int newId)    // Méthode non-constante
    {
        m_id = newId;
    }

private:
    int m_id = 0;
};
  • Pointeurs const et objets const
const int* pImmutableValue;  // Pointeur vers une valeur immuable
int const* pAlsoImmutable;   // Équivalent
int const value = 42;        // Objet immuable

Macros et Constantes

  • Préférez constexpr aux macros (#define) :
  • Utilisez constexpr pour définir des constantes au lieu de macros chaque fois que possible.
  • Les constantes déclarées avec constexpr sont plus sûres en termes de portée et de type.
// Utilisation de constexpr
constexpr int maxItems = 100;

// Évitez d'utiliser #define pour définir des constantes
#define MAX_ITEMS 100
  • Évitez les macros pour les fonctions :
  • Utilisez plutôt des fonctions en ligne (inline) ou des fonctions normales, car elles offrent des avantages en termes de sécurité et de débogage.
#define SQUARE(x) ((x) * (x))

// Utilisez une fonction en ligne ou normale
inline int square(int x) {
    return x * x;
}
  • Utilisez constexpr pour les fonctions évaluables à la compilation :
  • Déclarez vos fonctions comme constexpr lorsque cela est possible. Cela permet une évaluation à la compilation lorsque les arguments sont des constantes connues à la compilation.
// Utilisation de constexpr pour une fonction non membre
constexpr int multiply(int a, int b) {
    return a * b;
}
// Exemple d'utilisation à la compilation
constexpr int result = multiply(3, 4);  // Évalué à la compilation

Copies

  • Minimisez les copies inutiles dans les méthodes :
  • Évitez les copies inutiles d'objets en passant les arguments par référence ou par référence constante plutôt que par valeur. Les copies peuvent entraîner une surcharge inutile sur le système et impacter les performances.
class CDataProcessor {
public:
    // Utilisation de référence constante pour minimiser les copies
    void processData(const std::vector<int>& data) {
        // Traitement des données ici
    }
};

Utilisation Minimale de la Heap pour l'embarqué

  • Privilégiez la Stack :
  • Favorisez l'utilisation de la stack autant que possible pour allouer des variables locales et temporaires. La stack est plus rapide à accéder et libère automatiquement l'espace lorsqu'une fonction se termine.
void exampleFunction() {
    int localVar;  // Allocation sur la stack
    // ...
}
  • Limitation des Allocations Dynamiques :
  • Limitez l'utilisation d'allocations dynamiques sur la heap. Les allocations sur la heap peuvent entraîner une fragmentation de la mémoire et sont généralement plus lentes que les allocations sur la stack.
// Éviter autant que possible les allocations sur la heap
int* dynamicValue = new int;  // À utiliser avec précaution

Ressources pour s'améliorer en C++

The Cherno - C++ : https://www.youtube.com/watch?v=18c3MTX0PK0&list=PLlrATfBNZ98dudnM48yfGUldqGD0S4FFb