Newsgroup: it.comp.lang.c
Titolo: confronto C e C++

Salve a tutti,
domanda per quelli che hanno molta più esperienza di me(quindi quasi
tutti credo): se qualcuno vi chiedesse per quale motivo preferire il C
al C++ - motivazioni serie senza metterci parere di preferenza
personale - cosa rispondereste?
In linea di principio conosco le differenze tra i due, ma preferirei
avere il parere di persone più esperte: quello che non ho avuto modo
di avere è una profonda esperienza nell'uso degli stessi da poter
giudicare da me.
Grazie. Ciao.

 - cosa rispondereste?
Premettendo che la mia esperienza è piuttosto limitata, mi permetto di 
dire che gli aspetti del C che preferisco rispetto al C++ sono:
- l'assenza di ciò che astrae maggiormente la programmazione (classi, 
oggetti, ...)
- una maggiore libertà nell'uso dei tipi (dove il C++ è severissimo)
- l'immediatezza nell'agire più direttamente sulla macchina (il C++ mi 
pare di maggiore livello)
- maggiore creatività nella stesura del listato
Devo però aggiungere che si tratta più di percezione personale che di 
oggettiva differenza; tant'è che si può fare più o meno di tutto con 
entrambi; trovo affascinante la programmazione ad oggetti come supportata 
dal C++, con tutto ciò che essa comporta, ma apprezzo molto anche la 
limpidezza e immediatezza del codice C puro, che sembra fare le cose a 
modo suo, attraverso cast più o meno oscuri, operazioni complesse sui 
puntatori e cose simili, ma sempre egregiamente.
Saluti


Premesso che le mie prime esperienze risalgono ancora all'assembler e 
che ho fatto molta esperienza su sistemi embedded, ho sempre preferito 
usare il C per la sua maggior flessibilità nell'adeguarsi alle 
strutture dell'hardware ed agire direttamente su di esse.
Ciao
Giovanni
-- 
   A computer is like an air conditioner,
   it stops working when you open Windows.
   Registered Linux user #337974  < 
http://giovanni.homelinux.net/
 >

Se devo tralasciare i pareri personali preferisco il C al C++ per due
fatti:
1) e' piu' veloce compilare codice C che C++
2) e' piu' facile trovare un compilatore C standard che un compilatore
C++ standard.

 puntatori e cose simili, ma sempre egregiamente.
Mah. Quest'ultimo pensiero mi sembra non voglia dire molto...
-- 
-riko

 C++ standard.
A proposito... conosci qualche compilatore che supporti davvero C99?
-- 
-riko

 giudicare da me.
Pero' chiedi solo su it.comp.lang.c. Questo non e' un buon modo per
avere risposte di ambo le posizioni. ;)
-- 
-riko

 A proposito... conosci qualche compilatore che supporti davvero C99?
http://en.wikipedia.org/wiki/C99#Support_by_major_compilers
-- 
By ZeD

 personale - cosa rispondereste?
Il C++ è un linguaggio molto MOLTO complesso. Molto più di quello che 
può apparire a prima vista. E questo è il suo maggiore problema.
Un esempio per tutti: se dimentichi la parolina "virtual" davanti al 
distruttore di un oggetto polimorfo, in molti casi ottieni del codice 
apparentemente funzionante, ma con un grave problema di memory leak.
E.

 
http://en.wikipedia.org/wiki/C99#Support_by_major_compilers
Che si legge: "praticamente no". Il gcc c'e' ancora piuttosto lontano
(mancano alcune cose piuttosto critiche, di fatto). Gli altri sono piu'
indietro. 
Di Ch me ne frego... :P
Sembrerebbe che Sun studio sia l'unico. Purtroppo non posso usarlo. 
Intanto mi siedo e aspetto: probabilmente per quando saro' in pensione
sara' pure supportato il nuovo standard C++... <g>
-- 
-riko

 Mah. Quest'ultimo pensiero mi sembra non voglia dire molto...
Meno male che esistono i gruppi di discussione, dove non si discute ma si 
risponde tranquillamente a domande sperando che arrivi il genio di turno 
che illustra la sua verità (che ovviamente è assoluta). E meno male che 
queste persone si sentono superiori, e non perdono occasione di 
ricordarlo agli altri.
Quello che hai detto può essere validissimo o meno, così come può essere 
validissimo o meno quello che ho detto io; ma ci sono modi diversi di 
dire le cose. Un po' di buona educazione non fa male nemmeno qui!

 porcone in C e non in C++ sono piuttosto rari
Ovviamente era un assegnamento porcone e non un cast porcone.
-- 
-riko

 dire le cose. Un po' di buona educazione non fa male nemmeno qui!
No. Ci sono cose su cui si puo' discutere (C vs. C++ e' un esempio
tipico, non si giungera' *mai* ad una conclusione, se non in specifici
casi circostanziati e magari piuttosto ovvi).
Altre cose sono vere o false. 
-- 
-riko

> Se qualcuno vi chiedesse per quale motivo preferire il C al C++
Scrivere codice C++ implica conoscere la programmazione ad oggetti.
Se non la conosci BENE scrivi codice poco strutturato, che poi diventa poco 
leggibile anche da chi l'ha scritto.
Quando lavori in un team, questo aspetto si inasprisce, specie se il livello 
non è omogeneo.
Per dirti .. io uso abitualmente il C, e sto facendo prove in C++ : per 
iniziare ho perso un po di tempo per conoscere la sintassi, ma poi son 
passato subito ad un libro di pattern di programmazione ad oggetti. E questo 
non mi eviterà di scrivere programmi pessimi (spero solo all'inizio)! 

 alla grande. Ma non in tutti.
trovo che a livello embedded (specialmente in sistemi con risorse
molto limitate) C++ generi un po' troppo overhead e IMHO non e'
utilizzabile per questo motivo. Anche se ad esempio sono su un
progetto dove avrei la vita molto piu' facile se potessi usare classi/
oggeti e compagnia bella.
C'e' anche da dire che (sempre a livello embedded) a volte gia' e'
difficile trovare un compilatore C decente per un dato
microprocessore, trovarne uno per C++ e' come trovare il famoso ago
nel pagliaio.
Ciao Jack

 cosa rispondereste?
Io ti posso dare l'opinione di uno sciacquino della
programmazione... ma non so resistere a parlare bene del
C++. Se lo desideri si arriva molto vicini a prendere un
file .c, rinominarlo .cpp e farlo compilare, quindi
qualsiasi cosa o costrutto sia fattibile in C lo è anche
in C++ così non si pone il problema. A questo punto, se
hai bisogno di anche un piccolissimo sottinsieme delle
possibilità del C++ puoi modificare i sorgenti di
conseguenza in modo non traumatico. Questo, dicevo,
elimina alla radice ogni problema di confronto.
Di problema ne vedo solo uno. Ad alti livelli il C++
permette costrutti veramente complessi; io personalmente
non sono in grado di seguire un buon 30% di quel che si
dice nel NG sul C++. Spesso vengono fuori soluzioni per le
quali rimango a bocca aperta chiedendomi come un
compilatore possa gestire cose simili (in realtà lo fa
benissimo). Ne segue che è facile prendere abitudini
sbagliate, impostare soluzioni non naturali per il
linguaggio, trasferire un'eventuale mentalità involuta e
casinara sui costrutti e l'organizzazione del software. In
questo il C ti protegge, in parte a causa della sua
relativa semplicità. Il C++ che è almeno un ordine di
grandezza più "vasto", articolato e profondo, ti protegge
meno.
Ripeto, opinioni dell'ultimissimo ignorante... Ma passare
dal C al C++ mi ha cambiato la vita in meglio in una
misura che mai credevo possibile.
ciao ciao
Apx.

 utilizzabile per questo motivo. 
In base a cosa dici questo? Io non non credo che il C++ abbia in sč un 
overhead rispetto al C.
E.


Per forza ha overhead, senza contare cosa succede se si abilita lo
RTTI.
In ogni caso il problema della programmazione ad oggetti su
piattaforme embedded, secondo me, risiede nel fatto che, metre la
programmazione ad oggetti facilita il design e la scrittura del
codice, rende dall'altro lato impossibile seguire il flow del
programma.
Oltretutto, su piattaforme performanti (come grandi server) è
possibile prescindere completamente dal flow aumentando la complessità
del disegno software (grazie a comode astrazioni software come per
esempio gli eventi), mentre questo è in pratica impossibile su
macchine risicate con cicli macchina contati o quasi. Usare un
linguaggio ad oggetti in una condizione simile forza a non utilizzare
tutte quelle procedure od elementi che rendevano la scelta appetibile
in primo luogo.
Come si dice col vecchio paragone, non si può uccidere una mosca a
cannonate.

 RTTI.
Scusa, ma io alle dimostrazioni "per forza" non credo.
Ci sono numerose features di C++ che in un modo o nell'altro non sono
compatibili con dispositivi a bassa capacita' di calcolo *o* a bassa
memoria.
Tuttavia c'e' un ragionevole sottoinsieme di funzionalita' di C++ che
non hanno nessun motivo di generare particolare overhead in spazio e/o
in memoria.
Semmai viene da chiedersi se quel sottoinsieme di C++ sia
sufficientemente diverso e piu' comodo di C da giustificarne
l'esistenza.
Uccidiamo RTTI immediatamente. Uccidiamo anche metodi virtuali. Non
vogliamo andare a runtime a fare della roba. Ecco: il polimorfismo
dinamico e' sostanzialmente morto. Possiamo farne a meno? Kind of.
Possiamo sempre tornare a fare alcune porcate a-la-C. 
Direi che dobbiamo uccidere anche le eccezioni. O forse no... in
generale un buon compilatore C++ riesce a fare molto per non creare
overhead nel caso in cui sia preso il ramo buono. Bisognerebbe studiarci
sopra. Suppongo che in molti casi non si potrebbero avere.
Un altra cosa che potrebbe creare non pochi problemi e' la gestione dei
costruttori di oggetti globali. 
Ma i templates? E' tutta roba gestita e creata staticamente. Quale
potrebbe essere il problema? I nomi buffi degli oggetti generati?
Ecco, anche solo per i templates a me viene voglia di passare da C a
C++. Confesso. 
-- 
-riko


Ma sì, riempiamo il codice di parentesi angolate e doppi punti.
Leggere un codice C++ scritto come dio comanda è come leggere una
pizza ai quattro formaggi, solo che la pizza è più chiara e una volta
letta  la puoi anche mangiare.
Sono d'accordo che puoi non usare la maggior parte delle funzionalità
offerte dal C++, ma in quel caso perchè decidere di usarlo in primo
luogo?

 luogo?
Potrebbe essere che non mi vada di reimplementare a mano in C le
restanti cose che mi sono gia' offerte in C++. Potrebbe essere che trovi
sufficientemente comode per il compito quelle features.
Potrebbe anche essere che sto sbagliando e che per quel compito sarebbe
stato meglio usare C e basta. 
-- 
-riko

 memoria.
Ma il punto fondamentale è che se una feature ti serve, allora il C++ la 
implementa con il minimo overhead necessario (fino a prova contraria). 
Questa è stata una precisa scelta nella progettazione del C++. Ovvio che 
se dichiari tutte le funzioni virtuali, allora hai un inutile overhead, 
ma questa non è buona programmazione. Se una funzione la dichiari 
virtuale perché ti serve, allora non hai nessun overhead, avresti le 
stesse prestazioni che scrivendo il codice in C.
E.


Overhead (come dice il termine stesso) è qualsiasi cosa il sistema (il
compilatore, nel nostro caso) aggiunga "in più".
Per fare un esempio, in C chiamare una funzione non inline ha un
determinato overhead causato dal passaggio di variabili (probabilmente
sullo stack) ed un jump. Il programmatore sa che la sua chiamata a
funzione nel suo codice, una volta compilato, avrà un "overhead"
dipendente da vari fattori.
Ritengo di poter generalizzare senza sbagliare troppo dicendo che più
un linguaggio è ad alto livello più overhead viene introdotto
(ovviamente, visto che i programmatori scelgono un linguaggio ad alto
livello per scrivere meno codice).
Tutto questo non implica che l'overhead sia "il bene" o "il male", nè
significa che un brutto programma C senza overhead sia più performante
di un buon programma C++ con molto overhead.
In C++ basta pensare ai Kg di aggiunte per gestire funzioni virtuali
ed eccezioni. Ribadisco che sono d'accordo sul fatto che si possono
non utilizzare, ma a questo punto cosa si usa? :)
Ciao!

 non utilizzare, ma a questo punto cosa si usa? :)
Le funzioni virtuali, se servono, possono essere tranquillamente usate! 
Certo ci possono essere situazioni in cui uno switch è meglio di una 
funzione virtuale... però dipende dalle situazioni. Di per sé una 
funzione virtuale svolge il suo compito nel modo migliore possibile.
Ad esempio può essere utile utilizzare le classi e l'overloading degli 
operatori. Oppure, come ti è già stato detto, i template.
E.


A parte l'overloading delle funzioni che ha il solo compito di
offuscare i nomi per il linker quando il programmatore è troppo pigro
per cercare un nome per una funzione, quello degli operatori si porta
dietro un bel carico di overhead (richiamo automatico di costruttori
di copia, assegnamento etc.etc., che sono sì logici, ma non
espliciti).
Sui template già mi sono espresso :D

 operatori. Oppure, come ti è già stato detto, i template.
Addirittura usando per bene i template si puo' scrivere codice piu'
efficiente. Per esempio quasi tutto il codice che usa puntatori a
funzione puo' essere scritto templaticamente *senza* l'indirezione in
piu' (con piu' possibilita' di ottimizzazione, per giunta).
Per non parlare della possibilita' di fare partial evaluation tramite
templates, appunto.
-- 
-riko

 espliciti).
No. *Non* *e'* *vero*. Tutto questo overhead c'e' se chi scrive non
conosce il linguaggio e di conseguenza lo usa male. Scrivendo codice
sensato il compilatore puo' ottimizzare sostanzialmente tutto
l'ottimizzabile. Oltretutto la maggior parte degli operator "classici"
che uno ridefinisce prendono i parametri per const reference, quindi i
costruttori di copia *non* li usa. Anche per i valori di ritorno codice
come
Foo bar(...) {
    Foo res(...);
    ...;
    return res;
}
non chiama il costruttore di copia. Di fatto il compilatore costruisce
l'oggetto gia' nella porzione di stack allocata per il valore di ritorno
e quindi il costruttore di copia *non* e' chiamato. I casi comuni sono
tutti molto ben ottimizzati.
Ora io non sono credo particolarmente nei benchmark, il codice bisogna
vederlo volta per volta, etc etc etc. Ma per esempio nello shootout:
<
http://shootout.alioth.debian.org/u32q/benchmark.php?test=all&lang=gcc&
lang2=gpp>
 
Puoi vedere come nei test scelti, computazionalmente intensivi, g++ non
sia inferiore a gcc praticamente sempre. Sono piu' i casi in cui g++ e'
piu' veloce di quelli in cui e' piu' lento. Di fatto in un solo caso
rimane piu' lento (e sono piuttosto disposto a scommettere che sia colpa
del wrapper C++ a gmp e non di altro). 
In compenso spesso C usa meno memoria. 
Ora, a quei bench dai il peso che vuoi, possibilmente prossimo a 0. Ma
direi che almeno dovrebbero fare riflettere un paio di volte sul claim
secondo cui C++ inserirebbe overhead qua e la'. Cioe' direi C++
*potrebbe* introdurre overhead, ma i compilatori sono piuttosto bravi a
non farlo.
-- 
-riko


Visto che do, appunto, come peso ai benchmark zero, non trovo alcuno
spunto per dover riflettere.

 spunto per dover riflettere.
Quindi come spieghi il fatto che su alcuni programmi di esempio non solo
apparentemente C++ non introduca overhead ma anzi dia maggiori
possibilita' di ottimizzazione? 
Cioe' hai un fatto, hai dei programmi (al di la del fatto che siano
pubblicati a scopo di bench, sono tutti calcoli piuttosto tipici e
tipicamente utilizzati) che contraddice quello che sostieni.
Cambiano gli algoritmi? Mica e' vietato cambiarli anche in C eh. Li
chiunque puo' contribuire, sceglie un problema, lo implementa e lo
sottomette. Se fa meglio, bene. 
Poi io sono fatto cosi': quando ho dei dati ci rifletto, non trovo una
scusa per scartarli se contraddicono la mia visione.
D'altra parte con C++ io ci ho pure fatto diverse cose e sapendolo usare
posso garantirti che riesci ad essere piuttosto efficiente. I templates
ti consentono di fare generare codice in modo che in C semplicemente non
puoi fare, e dovresti aggiungere uno specializzatore a parte.
Ci sono features notoriamente meno efficienti: sono anche comode da
usare. Dopotutto fuori dall'embedded vale tranquillamente la 80/20.
Basta non usarle nel 20 (o nell'80 a seconda di che punto di vista
applichi). 
Se storicamente i compilatori C++ erano (molto) meno maturi di quelli C,
niente da dire. E' vero. Ma le cose cambiano, eh. C'e' molto codice che
senza i templates e' semplicemente un incubo da scrivere, e questo e' un
fatto. 
-- 
-riko


void *

 void *
Ottimo punto. Senza templates usi void*. Peccato che in questo modo
aggiungi fisso un livello di indirezione (che paghi, ovviamente) *e* non
sei typesafe (che puo' causare software non corretto). Non e' insomma
proprio una cosa indolore, dal mio punto di vista.
-- 
-riko


Di solito una lista (o un albero, o un grafo) li fai di puntatori a
qualcosa, quindi il "livello di indirezione" che dici te è confinato
in una serie di casi limitatissimi (riscrivibili staticamente anche in
C). Per quanto riguarda i tipi non c'è niente da dire, è possibile
sbagliare. Ma sia il C che il C++ sono debolmente tipizzati, e
"mischiare carote e patate" in C/C++ è sempre possibile con un cast
(carote+=(carote)patate); aggiungere un punto in più dove infilare un
cast in un intero programma è praticamente trascurabile.
Ciao!

 cast in un intero programma è praticamente trascurabile.
Assolutamente lo sono. Infatti e' una cosa che mal tollero. Intendo
dire, un typesystem statico abbastanza da rompere le palle e debole
abbastanza da non garantire nulla.
Ad ogni buon conto usando *bene* C++ certe cose non sono necessarie,
laddove in C lo sono. E vabbe', ci si vive eh. Ma non sono stato io ad
iniziare il C++ bashing. :P
-- 
-riko

 compilatore o esplicitamente la paghi comunque.
E' da qualche post che cerco di capire questa tua preoccupazione sugli 
oggetti non inizializzati. Se hai:
class T {
   int x;
   int y;
};
T fun() {
   return T();
}
direi che non hai nessun overhead. Il costruttore di default di T non 
deve fare assolutamente nulla e quindi ogni compilatore decente non fa 
assolutamente nulla. Il C++ non impone che le variabili di classe 
vengano inizializzate.
E.

 oggetti non inizializzati. 
Ma infatti io non *ho* preoccupazione. Sto dicendo anzi che non c'e' da
preoccuparsi perche' l'overhead quando c'e' non e' overhead perche' e'
voluto.
Un particolare non considero assolutamente buona pratica avere in giro
oggetti non inizializzati, ne in C ne in C++. Io *voglio* essere sicuro
che se vado ad accedere ad un oggetto dentro ci sia roba sensata. A
prescindere dal linguaggio.
Trovo appunto i costruttori una manna in questo senso. 
-- 
-riko

 prescindere dal linguaggio.
Diciamo che se ci tieni molto alle prestazioni può capitare di avere 
variabili non inizializzate in giro... e magari hai dei flag che ti 
dicono se le variabili sono inizializzate o meno. Quello che voglio dire 
è che neanche in questo caso il C++ ti limita. Se un costruttore di un 
oggetto non fa niente, allora la costruzione dell'oggetto non costa nulla.
E.

 oggetto non fa niente, allora la costruzione dell'oggetto non costa nulla.
Si. Non mi vengono in mente limitazioni effettive. 
Le uniche sono che C++ e' molto piu' complesso da imparare di C (e
questo e' un fatto) e che un compilatore C++ (dal front-end al back-end)
e' molto piu' complicato da scrivere e da scrivere bene.
-- 
-riko

Jack ha scritto:

un esempio potrebbe essere qui (confronto g++ con gcc):
http://shootout.alioth.debian.org/gp4/benchmark.php?test=all&lang=gcc&lang2=gpp

 
http://shootout.alioth.debian.org/gp4/benchmark.php?test=all
〈=gcc...
http://shootout.alioth.debian.org/u32q/c.php