Oh sì, è usato. Lavoro nel campo dell'elaborazione dei pacchetti di rete. Sono stato in due diverse società in cui elaboriamo pacchetti di rete. Quindi, operiamo a livello Ethernet o IP, non al livello superiore a TCP.
È interessante notare che in entrambe le società C è stata scelta su C ++. In una delle aziende, uno dei due prodotti è stato costruito su un kernel Linux, mentre l'altro prodotto è stato creato nello spazio utente di Linux. Il prodotto del kernel usava ovviamente C come il kernel di Linux è programmato in C, ma hanno scelto di usare anche C per il prodotto userspace. Entrambi i prodotti sono stati sviluppati a partire dal 2000 circa (il prodotto del kernel un po 'prima del 2000 e il prodotto userspace un po' dopo il 2000).
Nell'azienda in cui sono andato dopo, il prodotto è stato costruito su C, non su C ++. In realtà è una continuazione di un progetto a partire dalla metà degli anni '90, anche se a causa delle recenti richieste di miglioramento delle prestazioni, è stato deciso che sostanzialmente tutto sarà riscritto. Avevamo un'opzione per selezionare C ++ a causa di questa riscrittura, ma non l'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 andare per MurMurHash3 . Forse voglio sicurezza e andare per SipHash . Gli allocatori di memoria sono ovviamente personalizzati. Di fatto, tutte le strutture di dati importanti che utilizziamo sono state implementate su misura per le massime prestazioni possibili.
Anche se non c'è nulla che possa impedire l'uso di C ++, di solito è una cattiva idea. Una singola eccezione generata per pacchetto farà cadere la velocità di elaborazione dei pacchetti a livelli inaccettabili! Quindi, non possiamo usare le eccezioni di C ++. Troppo lento. Stiamo già utilizzando un codice C di tipo orientato agli oggetti implementando strutture di dati come strutture e implementando quindi le funzioni che operano su tali strutture. Il C ++ consentirebbe di avere funzioni virtuali, ma poi di nuovo le chiamate alle funzioni virtuali ucciderebbero le prestazioni se usate ovunque. Quindi, è meglio essere espliciti e avere un puntatore a funzione se sono necessarie le chiamate alle funzioni virtuali.
C ++ farà un sacco di cose dietro la schiena: allocazione di memoria, ecc. D'altra parte, in C di solito non accade. Puoi scrivere una funzione che alloca la memoria, ma di solito è evidente dall'interfaccia della funzione che sta avvenendo l'allocazione.
Come esempio del tipo di micro-ottimizzazioni che è possibile eseguire durante la programmazione in C, dai un'occhiata al contenitore_di macro nel kernel di Linux. Certo, potresti usare container_of in codice C ++, ma chi lo fa? Voglio dire, è del tutto accettabile nella maggior parte dei programmi in C, ma i tipici programmatori C ++ propongono immediatamente qualcos'altro, come una lista concatenata che assegna i nodi di collegamento come blocchi separati. Non lo vogliamo perché ogni blocco di memoria assegnato fa male alle prestazioni.
Forse l'unica cosa che ci avvantaggerebbe in C ++ è che C ++ consente la metaprogrammazione del modello, il che significa che a volte è possibile evitare chiamate di funzioni virtuali pur avendo un parametro di funzione e consentire al compilatore di integrare 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à, in realtà disponevamo di un linguaggio personalizzato compilato in cui sono state implementate parte delle funzionalità. Indovina qual è stata la lingua di destinazione del compilatore? Assemblea? No, dovevamo supportare entrambe le architetture a 32 e 64 bit. C ++? Sicuramente scherzi. Ovviamente, era C con GCC goto calcolato . Quindi, il linguaggio personalizzato è stato compilato in C (o in realtà la variante gcc di C che supportava goto calcolato) e il compilatore C ha prodotto l'assembly.