ProgrammazioneSviluppatore C

Parlami delle principali differenze tra const e #define per la definizione di costanti nel linguaggio C. Quando e perché utilizzare ciascun approccio, con esempi di errori tipici?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

#define è una direttiva del preprocessore che sostituisce semplicemente tutte le occorrenze dell'identificatore con il valore prima della compilazione. Non crea variabili, non conosce i tipi, non verifica i limiti e non rispetta l'ambito.

const è un qualificatore che crea una vera variabile, ma bloccata in scrittura dopo l'inizializzazione. Una variabile const ha un tipo, un ambito, partecipa al debugging e può essere più sicura. Queste variabili vengono allocate nella sezione .rodata o nello stack/in memoria.

Quando e perché usare:

  • #define — per valori scalari semplici necessari in fase di compilazione, specialmente se utilizzati in condizioni del preprocessore o dimensioni di array (#define SIZE 16).
  • const — per valori che devono essere passati in modo sicuro dal punto di vista dei tipi, debuggati e in modo sicuro esportati (nei file di intestazione, tra moduli).
  • Per puntatori a stringhe e array, è preferibile usare const.

Esempio:

#define PI 3.14159 const double G = 9.81; int arr[PI]; // ERRORE! PI non è un intero int arr2[G]; // ERRORE! G non è un valore di tempo di compilazione

Domanda insidiosa.

Domanda: Funziona const int a = 10; come costante di tempo di compilazione per creare un array: int arr[a];?

Risposta: No. Nel linguaggio C const è un qualificatore, ma la variabile viene creata e inizializzata durante l'esecuzione, e non durante la compilazione, quindi la dimensione dell'array deve essere un letterale o un'espressione nota al compilatore. Utilizzare #define, oppure enum { SIZE = 10 };.

Esempio di errore:

const int a = 5; int arr[a]; // In C89/90 non funzionerà (VLA sono apparsi in C99, ma non ovunque)

Storia

Nel media server si è tentato di utilizzare const int per impostare le dimensioni del buffer, pensando che fosse una "costante di tempo di compilazione". Su un compilatore (GCC, C99) tutto funzionava, ma su molti altri c'era un errore di compilazione (VLA non supportati), si è dovuto riscrivere urgentemente con #define.


Storia

In codice dipendente dalla piattaforma, si è definita una stringa tramite #define NAME "MyApp", utilizzata in più punti e dimenticata di metterla tra parentesi. Dopo l'aggiunta di caratteri alla stringa senza esplicite parentesi si ottenevano risultati sbagliati, portando a bug strani nei log.


Storia

In un progetto con più moduli, si è definita una costante tramite #define in due punti con valori diversi (copia e incolla). Il risultato — i moduli lavoravano con costanti diverse, portando a non conformità dei dati, correggibili solo con un attento debugging.