Oh sì, è usato. Lavoro nel campo dell'elaborazione di pacchetti di rete. Sono stato in due diverse società in cui elaboriamo i pacchetti di rete. Quindi, stiamo operando a livello Ethernet o IP, non a livello superiore a TCP.
È interessante notare che in entrambe le società C è stato scelto rispetto al C ++. In una delle società, uno dei due prodotti è stato creato sopra il kernel Linux, mentre l'altro prodotto è stato creato nello spazio utenti Linux. Il prodotto del kernel ovviamente usa C come kernel Linux è programmato in C, ma hanno scelto di usare anche C per il prodotto userspace. Entrambi i prodotti sono stati sviluppati a partire dall'anno 2000 circa (il prodotto kernel un po 'prima del 2000 e il prodotto userspace un po' dopo il 2000).
Nella società in cui sono andato dopo, il prodotto è stato costruito su C, non su C ++. Si tratta in realtà di una continuazione di un progetto a partire dalla metà degli anni '90, sebbene a causa delle recenti richieste di miglioramento delle prestazioni, si decise che essenzialmente tutto sarebbe stato riscritto. A causa di questa riscrittura avevamo un'opzione per selezionare C ++, ma non lo abbiamo fatto.
Nel campo dell'elaborazione dei pacchetti di rete, le prestazioni contano molto. Quindi, voglio implementare la mia tabella hash con prestazioni più elevate rispetto alle tabelle hash esistenti. Io, non l'autore della tabella hash, sono chi seleziona quale funzione hash deve essere utilizzata. Forse voglio prestazioni e scelgo MurMurHash3 . Forse voglio sicurezza e scelgo SipHash . Gli allocatori di memoria sono ovviamente personalizzati. In effetti, tutte le importanti strutture dati che utilizziamo sono state implementate su misura per le massime prestazioni possibili.
Mentre non c'è nulla che possa impedire l'uso del C ++, di solito è una cattiva idea. Una singola eccezione generata per pacchetto ridurrà la velocità di elaborazione dei pacchetti a livelli inaccettabili! Quindi, non possiamo usare le eccezioni di C ++. Troppo lento. Stiamo già utilizzando un tipo di codice C orientato agli oggetti implementando strutture di dati come strutture e quindi implementando funzioni che operano su tali strutture. Il C ++ consentirebbe di avere funzioni virtuali, ma ancora una volta le chiamate alle funzioni virtuali ucciderebbero le prestazioni se utilizzate ovunque. Quindi, è meglio essere espliciti e avere un puntatore a funzione se sono necessarie chiamate a funzioni virtuali.
Il C ++ farà molte cose alle tue spalle: allocazione della memoria, ecc. D'altra parte, in C che di solito non accade. È possibile scrivere una funzione che alloca memoria, ma di solito dall'interfaccia della funzione è evidente che l'allocazione sta avvenendo.
Come esempio del tipo di micro-ottimizzazioni che puoi fare durante la programmazione in C, dai un'occhiata alla macro container_of nel kernel di Linux. Certo, potresti usare container_of nel codice C ++, ma chi lo fa? Voglio dire, è del tutto accettabile nella maggior parte dei programmi C, ma i programmatori C ++ tipici proporrebbero immediatamente qualcos'altro, come un elenco collegato che alloca i nodi di collegamento come blocchi separati. Non lo vogliamo perché ogni blocco di memoria allocato è dannoso per le prestazioni.
Forse l'unica cosa che ci trarrebbe beneficio in C ++ è che C ++ consente la metaprogrammazione dei modelli, il che significa che a volte puoi evitare chiamate di funzione virtuali pur avendo ancora un parametro di funzione e consentire al compilatore di incorporare le funzioni. Ma la metaprogrammazione dei modelli è complicata e siamo riusciti a soddisfare tutti i requisiti in C, quindi il vantaggio di questa funzionalità in C ++ non è così critico.
In una delle società, avevamo effettivamente un linguaggio compilato personalizzato in cui erano implementate parte delle funzionalità. Indovina qual era la lingua di destinazione del compilatore? Assemblea? No, abbiamo dovuto supportare architetture a 32 e 64 bit. C ++? Sicuramente scherzi. Ovviamente, era C con il goto calcolato di GCC . Quindi, il linguaggio personalizzato è stato compilato in C (o in realtà la variante gcc di C che supportava goto calcolata) e il compilatore C ha prodotto assembly.