Files
Cours-C/ch002-env.md

3.0 KiB
Raw Blame History

Chapitre 2 — Environnements et portabilité

2.1 C hébergé vs C freestanding

Il existe deux modes dexécution du C.

Un environnement hébergé fournit :

  • un OS
  • une libc complète
  • un point dentrée main
#include <stdio.h>

int main(void)
{
    printf("Hello\n");
    return 0;
}

Un environnement freestanding est minimal.

void start(void)
{
    // code bas niveau
}

2.2 Plateformes

Linux, Windows, macOS ont des APIs différentes.
Un programme C peut sexécuter sur plusieurs systèmes. Mais tous les systèmes sont différents.


  • Linux
    • API POSIX
    • forte portabilité
    • outils standards

  • macOS
    • basé sur UNIX
    • proche de POSIX
    • spécificités Apple

  • Windows
    • API spécifique (WinAPI)
    • comportement différent sur certains points
    • pas POSIX natif

  • Android
    • basé sur Linux
    • libc spécifique (Bionic)
    • contraintes mobiles

  • Embarqué
    • pas dOS ou OS minimal
    • ressources limitées
    • accès direct au matériel

2.3 Architecture vs système

Un programme dépend de plusieurs couches.

Il faut distinguer :

  • architecture (CPU)
  • système (OS)
  • compilateur

🔹 Architecture

Exemples :

  • x86
  • x86_64
  • ARM
  • RISC-V

Chaque architecture :

  • a ses registres
  • son alignement
  • son endianness

🔹 Système

Le système fournit :

  • fichiers
  • processus
  • mémoire

🔹 Compilateur

Il traduit le code C en binaire.

Exemples :

  • gcc
  • clang
  • compilateurs embarqués

2.4 Endianness

Lendianness définit lordre des octets en mémoire.

🔹 Little endian

Octet faible en premier.

🔹 Big endian

Octet fort en premier.


Exemple :

#include <stdio.h>

int main(void)
{
    int x = 0x12345678;
    unsigned char *p = (unsigned char*)&x;

    printf("%02x %02x %02x %02x\n", p[0], p[1], p[2], p[3]);
}

Le résultat dépend de larchitecture.


2.5 Taille des types

La taille des types nest pas fixe.


Exemple :

#include <stdio.h>

int main(void)
{
    printf("%zu\n", sizeof(int));
}

2.6 Ce qui est portable

Code portable :

  • respecte la norme
  • évite les extensions
  • évite les hypothèses

Exemple — non portable

int main(void)
{
    int x = 2147483647 + 1; // overflow

    return 0;
}

Le comportement nest pas défini.


Exemple — portable

#include <stdint.h>

int main(void)
{
    int32_t x = 2147483647;

    return 0;
}

2.7 Dépendances système

Certains appels dépendent du système.


Exemple :

#include <stdlib.h>

int main(void)
{
    system("ls"); // Linux uniquement

    return 0;
}

2.8 Abstraction

Pour être portable, il faut abstraire.

Cela signifie :

  • isoler le code dépendant
  • utiliser des interfaces

--

Exemple :

void afficher_message(void)
{
#ifdef _WIN32
    // Code Windows
#else
    // Code Linux ?
#endif
}

2.9 Bonnes pratiques

  • utiliser <stdint.h>
  • éviter les tailles implicites
  • éviter UB
  • tester sur plusieurs plateformes
  • isoler le code système