Guida Frequently asked questions: da dove si parte?

St3ve

Utente Jade
12 Ottobre 2011
2,442
5
1,850
686
Ultima modifica:
Introduzione
Visti i numerosi post a riguardo, mi sono deciso a rispondere a quelle che potrebbero essere le domande di chi ha intenzione di avvicinarsi alla programmazione in C e C++.
Iniziamo subito a chiarire un luogo comune: non c'è bisogno di imparare il C prima di imparare il C++. Così come noi italiani abbiamo imparato subito l'Italiano, senza imparare prima il latino, perché l'Italiano è la lingua che necessitavamo per comunicare con la gente, anche chi ha scelto (per volontà o necessità) di imparare il C++ non deve perdere tempo ad imparare il C. Tuttavia se per scelta vostra avete intenzione di imparare entrambi i linguaggi, allora la strada più logica è imparare il C prima del C++.
Se volete semplicemente imparare un linguaggio di programmazione, ma non avete nessun progetto in mente e non siete in grado di scegliere tra C o C++ (o altri linguaggi), allora riceverete quasi esclusivamente delle risposte opinabili basate sull'esperienza che ha avuto chi vi risponde e dalle sue preferenze. Quindi se volete un consiglio sul linguaggio da imparare otterrete due tipi di risposte: quelle basate sul vostro obbiettivo (ammesso che ne abbiate uno), oppure quelle basate sulle esperienze e preferenze di chi vi risponde.

Quali sono le principali differenze tra questi due linguaggi?
Il C è un linguaggio molto snello e semplice, rimasto quasi invariato dalla sua prima standardizzazione (1989), mentre il C++ è uno dei linguaggi più grandi che vi capiterà di incontrare. Il C++ non è pulito come il C, il C++ che abbiamo adesso è frutto di innumerevoli cambiamenti nello standard dove la parola d'ordine è retrocompatibilità: se una feature del linguaggio al giorno d'oggi viene ritenuta superflua o addirittura dannosa, non la vedremo rimossa in futuro.
Queste modifiche (o meglio, aggiunte) allo standard hanno permesso al C++ di essere sempre moderno, tuttavia il fatto che non sia un linguaggio progettato in una volta sola lo ha reso molto poco pulito e disordinato: ci sono diversi modi molto diversi tra loro per ottenere risultati concettualmente identici, ma tecnicamente molto diversi.
Quando è nato il C++, è stato pensato per essere un superset del C: una grossa porzione dei programmi in C possono essere compilati in C++ senza cambiare una riga di codice. Tuttavia non vuol dire che se imparate il C++, state imparando anche il C senza fare la doppia fatica, prima di tutto perché imparare il C++ è molto più difficile che imparare il C e in seconda battuta perché il C++ moderno ha poco a che fare con il C.
Tra alcune delle più importanti features presenti in C++, ma non in C, vi cito: paradigma object-oriented, programmazione generica e metaprogrammazione, exception handling, overloading di funzioni e operatori e supporto basilare al paradigma funzionale. Se non sapete il significato di questa roba passate avanti senza dargli molta importanza o chiedete spiegazioni, non voglio divagare troppo.
Sostanzialmente, sebbene siano apparentemente simili, sono due linguaggi molto diversi tra loro, sia per mentalità (uno minimale, l'altro enorme) che per caratteristiche. Siamo arrivati al punto che il C++ è talmente grande che sebbene il C ne sia quasi interamente una sottoparte, questa sottoparte è molto piccola. Inoltre nelle regole che definiscono quello che è un codice moderno in C++, le caratteristiche verbalmente deprecate sono in gran parte quelle derivate dal C.

Quali sono i vantaggi di programmare in C e quali in C++?
Risposta. Per motivi pratici mi sono concentrato solo sui vantaggi del C++ rispetto al C e vice versa, se qualcuno fosse interessato ad un confronto diretto rispetto ad un altro linguaggio, basta che chieda. In generale C e C++ sono i linguaggi principali (più diffusi e più convenienti da utilizzare) quando si necessitano alte prestazioni oppure operazioni a basso livello.

Cosa devo installare per programmare con uno di questi due linguaggi?
Gli unici programmi indispensabili sono un text editor (altrimenti come li scrivete i codici?) e un compilatore, ovvero il programma che traduce il vostro codice in un codice binario comprensibile dal computer. Detto banalmente: il programma che vi genera l'eseguibile.
Tuttavia la scelta più gettonata è quella di installare un IDE (Integrated Development Environment - ambiente di sviluppo integrato), ovvero un programma che contiene oltre al compilatore e al text editor una serie di tools che vi semplificano la vita durante lo sviluppo. Gli IDE solitamente vi forniscono funzionalità come sintax highlighting, autocompletamento, controllo degli errori in fase di scrittura, linking delle dipendenze automatico, debugger, eccetra eccetra...
Il mio consiglio, visto che siete agli inizi, è di partire direttamente con un IDE, che è il classico strumento che viene usato in ambito professionale. Se poi vi trovate male e/o volete vedere e capire cosa fa l'IDE in maniera automatica, passate ad un text editor + compilatore e avete piena visione su cosa sta succedendo. Poi una volta che imparate a muovere i primi passi sarete in grado di scegliere cosa preferite fare.
Dato che il C++ è quasi interamente un superset del C, potete capire che alcuni IDE impostano un compilatore C++ di default. Imparare il C usando un compilatore C++ non è il massimo della vita, quindi prima assicuratevi di aver impostato correttamente il vostro IDE.

Alcuni degli IDE che vi consiglio sono: Visual Studio (Windows), Eclipse (multipiattaforma), Code::Blocks (multipiattaforma), QtCreator (multipiattaforma), XCode (mac), CLion (multipiattaforma) e NetBeans (multipiattaforma). Tutti questi IDE permettono di programmare in C, in C++ e in altri linguaggi (a seconda dell'IDE). Se state programmando in C vi sconsiglio l'uso di Visual Studio, visto che è meno intuitivo dirgli di compilare in C e il suo compilatore C è mantenuto a stento (per il C++ invece è molto valido).

Ma soprattutto vi sconsiglio di usare DevCpp: è un IDE purtroppo molto conosciuto (perché?), ma fa veramente schifo e i principianti non sono in grado di accorgersene. Evitate di partire con abitudini sbagliate.

Se volete usare un semplice text editor (notepad, vim, gedit, sublime text, emacs o quello che vi pare), i compilatori che potete usare sono principalmente tre: MinGW-w64 (windows), GCC (linux), Clang (mac e linux). Per compilare dovete aprire il terminale (prompt dei comandi) e digitare un codice di questo tipo:
Codice:
# Compilare il C
gcc -o nome_eseguibile nome_file.c  # sia gcc che minwg-w64
clang -o nome_eseguibile nome_file.c  # clang

# Compilare il C++
g++ -o nome_eseguibile nome_file.c  # sia gcc che minwg-w64
clang++ -o nome_eseguibile nome_file.c  # clang

In ogni caso la questione text editor vs IDE è discutibile. Ci sono developers molto famosi che preferiscono usare text editors, ad esempio Linus Torvalds utilizza uEmacs (micro Emacs), un text editor molto semplice. Sono per lo più casi particolari, ma visto che se n'è discusso in passato vi rimando a questa discussione.

Che guida devo usare?
Inglese
Per il C:
The C Programming Language, C Programming A Modern Approach, C Primer Plus, Head First C
Per il C++: The C++ Programming Language, Programming Principles and Practices Using C++, Thinking in C++, C++ Primer

Italiano
Per il C:
Il Linguaggio C (K&R), Programmazione in C, Il Linguaggio C Fondamenti e Tecniche di Programmazione (Deitel&Deitel)
Per il C++: C++ Linguaggio Libreria Standard Principi di Programmazione, C++ Fondamenti di Programmazione, Pensare in C++

Se volete ulteriori libri vi invito ad usare il tasto cerca e a sfogliare questa discussione.
La maggior parte di quelli che ho linkato sono a pagamento, credo che l'unica eccezione sia Thinking in C++ (Pensare in C++), ma nella discussione che ho linkato ne trovate degli altri. Comunque sia sentitevi liberi da partire da quello che volete, anche se usare un libro è altamente consigliato. Se avete altri libri non è un grosso problema: anche solo per il fatto che si sono meritati la carta stampata, vuol dire che come risorsa non sono malaccio.

Tra le altre risorse utili, da usare come riferimento quando avete qualche dubbio mentre programmate, vi linko: http://en.cppreference.com/w/, http://www.cplusplus.com/reference/, http://linux.die.net/man/
Da questi link potete ricercare funzioni, classi e quant'altro per avere una documentazione su come vanno usate. Il terzo link (il manuale linux) è per il C, mentre gli altri due sono principalmente per il C++ (ma sono rilevanti anche per il C).

Come capisco che standard sto usando?
Se siete degli studenti, alcuni professori vi richiederanno di utilizzare uno standard ben preciso del linguaggio. Se volete sperimentare per i fatti vostri, può essere che siate interessati ad usare qualche feature nuova, ma il compilatore è impostato per compilare con una versione vecchia.
Ogni IDE e ogni compilatore ha un modo diverso per impostare la versione dello standard da utilizzare (a patto che sia supportata), di default tendono ad usare lo standard più recente a patto che questo sia supportato sufficientemente. Il procedimento per cambiare la versione dello standard utilizzata dipende dal vostro IDE e dal vostro compilatore, se avete qualche richiesta scrivetela che la aggiungo in questa sezione.

Ad esempio se volete compilare in ANSI C (standard C del 1989) usando clang e gcc, dovete usare la seguente sintassi:
Codice:
gcc -ansi -o nome_eseguibile nome_file.c
clang -ansi -o nome_eseguibile nome_file.c


Il mio codice ha un errore o non fa quello che mi aspetto. Come chiedo aiuto?
È importante specificare dettagliatamente cosa ti aspetti di ottenere e cosa ottieni, postare un esempio di input/output ottenuti e aspettati è un buon punto di partenza. È inoltre necessario postare il pezzo di codice che non funziona (più è grande e meglio è, se è tutto il codice è più facile per noi aiutarti) e in caso di errore è molto utile postare l'errore che che viene segnalato dal compilatore (letteralmente un copia/incolla dell'errore). Dato che abbiamo sottolineato che C e C++ sono due linguaggi distinti, mentre noi abbiamo una sezione unica per i due, è molto utile dire quale dei due si sta utilizzando.

Esistono due tipi di avvisi: Error e Warning. Gli Error sono errori veri e propri, se hai un error il tuo codice non viene compilato, mentre i Warning sono degli avvisi. Il compilatore usa gli avvisi per segnalarti che hai scritto un codice compilabile (la sintassi è corretta e il codice viene effettivamente compilato), ma probabilmente hai fatto un errore di distrazione.

Quando avvio l'eseguibile non vedo niente, anche se il programma è corretto. Dove sbaglio?
Tutti i programmi quando finiscono di fare quello che devono fare, si chiudono. Supponiamo che hai questo programma (lo scrivo in C, ma è un discorso valido anche in C++)
C:
#include <stdio.h>

int main()
{
  printf("Hello World\n");
  return 0;
}
Se lo avvii con il classico doppio click, il programma si apre, stampa "Hello World" e si chiude nel giro di qualche millisecondo. Per vedere bene cosa succede bisogna avviare il programma da terminale, in questo modo sebbene il programma termini, la console rimane aperta (dato che non è stata lanciata dal tuo programma) e tu hai l'opportunità di leggere l'output.
Se vuoi che il tuo programma resti aperto anche con l'avvio da doppio click, allora lo devi programmare in modo tale che attenda qualcosa prima di uscire, ad esempio:
C:
/* Codice C */
#include <stdio.h>

int main()
{
  /* int c; */ /* necessario se decommentate le righe sotto */
  printf("Hello World\n");
  /* while ((c = getchar()) != '\n' && c != EOF);  */ /* flusha il buffer stdin */
  getchar();  /* resta in attesa della pressione di un tasto (prendi in input un carattere) */
  return 0;
}
C++:
// Codice C++
#include <iostream>

int main()
{
  std::cout << "Hello World" << std::endl;
  // std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n') // flusha il buffer stdin
  // std::cin.clear(); // pulisci le error flags, correlato all'istruzione precedente
  std::cin.get();
  return 0;
}

Avrete probabilmente spesso incontrato system(pause) per risolvere questo problema, tuttavia è una soluzione pessima dato che chiede l'intervento del sistema operativo per risolvere un problema molto semplice. Se potete evitare di usarlo, e potete sempre evitarlo, non usatelo. Vi complicate un po' di più la vita, ma risolvete il problema in un modo più corretto.
Se il codice che vi ho fornito precedentemente non dovesse funzionare, è perché rimane della sporcizia nel buffer stdin. In questo caso rimuovete i decommentate le righe e leggete il punto dedicato a questo problema.

L'input non funziona correttamente, l'utente non ha la possibilità di inserirlo. C'è della sporcizia nel buffer stdin.
Generalmente la gestione dell'input e dell'output è una cosa che sembra semplice e scontata (per motivi pratici è tra le prime cose che si impara), ma non lo è. Qui, per motivi pratici, do solo un overview del problema e di come risolverlo, se volete qualche dettaglio in più non vi resta che chiedere.

Cos'è il buffer stdin?
Tutto l'input del terminale passa per attraverso il buffer di stdin (standard input). Questo stdin è sostanzialmente un grosso array di caratteri che vi permette di leggere tutto l'input in una botta sola. Detto banalmente, quello che vi interessa sapere è che ogni volta che avete a che fare con l'input dal terminale, state prelevando (andate proprio ad estrarre) parte del contenuto di questo stdin. Quando chiedete un input all'utente, il programma controlla se c'è qualcosa da leggere nel buffer stdin: se c'è qualcosa allora legge direttamente da li, altrimenti il programma si blocca in attesa che l'utente scriva qualcosa.

Cosa può andare storto?
Principalmente le problematiche sono due: state prelevando una porzione di buffer più piccola di quella che a voi interessa oppure avete della sporcizia (dati che non vi interessano) nella parte iniziale di questo buffer. Come è facile intuire queste due problematiche sono abbastanza vicine tra loro: se prima non leggete tutta la parte che vi interessa, dopo avrete la prima parte del buffer con dei valori non attesi.
In questa sezione discutiamo della sporcizia nel buffer stdin.

Come capisco se ho questo problema?
Partendo dal presupposto che ogni volta che aprite il programma, il buffer stdin è pronto all'uso (è pulito), la problematica tipica è che il programma vi salta delle richieste di input. Come abbiamo detto, se c'è qualcosa nel buffer stdin non è richiesto l'intervento dell'utente. Quindi se credete di dover inserire un input, ma invece il programma prosegue, probabilmente rientrate in questo problema.
Ovviamente non è scontato che il problema sia questo, per capire bene cosa succede dovete avere un po' più di esperienza e magari utilizzare un debugger. Ma questo è un problema tipico causato dalla sporcizia nel buffer stdin.

Come risolvo questo problema?
La funzione che avrete probabilmente incontrato è fflush(stdin), ma non è una soluzione portable visto che lo standard C (e quindi per ereditarietà anche lo standard C++) dice esplicitamente che il comportamento di questa funzione su dei buffer di input non è specificato. Evitate di usarla.
Non esiste una funzione standard per flushare (letteralmente "scaricare") il buffer di input, quello che potete (e dovete) fare è ignorare questa prima parte di buffer che contiene della sporcizia. Lo fate in questo modo:
C++:
// C++
std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n') // flusha il buffer stdin (ignora fino al carattere '\n')
std::cin.clear(); // pulisci le error flags
// adesso puoi prendere l'input
C:
/* C */
int c;
while ((c = getchar()) != '\n' && c != EOF);  /* flusha il buffer stdin (ignora fino a '\n' oppure fino a end of file) */
/* adesso puoi prendere l'input */

Stiamo ignorando fino al carattere di '\n' (a capo) perché tipicamente la sporcizia che troviamo nel buffer è delimitata da un carattere '\n'. Questo problema può capitare, ad esempio, se usiamo getchar() per leggere un singolo carattere: l'utente oltre ad inserire il carattere che noi stiamo prelevando preme invio (per dire: "ho terminato di scrivere"), però l'invio inserisce il carattere '\n'. Quindi noi ci aspettiamo di leggere un carattere, ma l'utente inserisce una stringa composta dal carattere + l'invio. Questo '\n' rimane nel buffer stdin che, se non lo ripuliamo/ignoriamo, lo preleveremo alla successiva richiesta di input (apparentemente, "salteremo" una richiesta di input).

Altro
Se c'è qualche domanda che vi piacerebbe vedere in questa lista o se parte di quello che ho detto non è chiaro o sembra sbagliato, segnalatelo nei commenti e provvederò a fixxare quel che serve. Stessa cosa se volete qualche approfondimento o cose del genere.
Ovviamente siete invitati a leggere anche il resto del thread!
 
Io avrei un dubbio: quali sono i vantaggi di programmare in C e quali in C++ (a parte la sintassi più basilare del C) ?
La sintassi non è cosa da poco, se hai regole strette sei obbligato a scrivere buon codice. Né il C e (soprattutto) né il C++ sono dei bei linguaggi da questo punto di vista, però se vuoi lavorare low level non hai grandi alternative. Negli ultimi anni stanno uscendo dei linguaggi che puntano a rimpiazzarli entrambi, ma attualmente sono troppo acerbi e non sufficientemente utilizzati.

Il C++ è il linguaggio più utilizzato in tutti i grandi progetti che richiedono molta performance (eg. rendering engines, DBMS, compilatori) mentre il C è il linguaggio più utilizzato per i progetti dove si lavora veramente low level (eg. kernel dei sistemi operativi, drivers, applicazioni embedded, ecc...). Poi molte volte si sceglie in base alla propria filosofia di pensiero: la JVM è scritta in C++, l'interprete di python è scritto in C, le Qt sono scritte in C++, le GTK sono scritte in C++, ecc...
Spesso è meglio partire fin da subito con un linguaggio che ti pone qualche limite in più invece che scendere a compromessi sulle features da utilizzare.

I vantaggi di usare il C++ invece del C direi che sono abbastanza ovvi: come ho già scritto nel open post, il C++ ha molte features in più ed è quasi interamente un superset del C. Se stai iniziando un nuovo progetto difficilmente sarai tentato dallo scegliere il C, ma allora perché c'è ancora tanta gente che lo usa ugualmente? È meno ovvio da capire, soprattutto per i neo-programmatori, ma spesso avere troppe features ti porta ad avere grandi problemi. A tal proposito ti cito un famoso post di Torvalds:
C++ is a horrible language. It's made more horrible by the fact that a lot of
substandard programmers use it, to the point where it's much much easier to
generate total and utter crap with it. Quite frankly, even if the choice of C
were to do *nothing* but keep the C++ programmers out, that in itself would be a
huge reason to use C.

C++ leads to really really bad design choices. You invariably start using the
"nice" library features of the language like STL and Boost and other total and
utter crap, that may "help" you program, but causes inefficient abstracted
programming models where two years down the road you notice that some
abstraction wasn't very efficient, but now all your code depends on all the nice
object models around it, and you cannot fix it without rewriting your app.

So I'm sorry, but for something like git, where efficiency was a primary
objective, the "advantages" of C++ is just a huge mistake.



Nota: ho fatto un po' di cherry picking. Il testo riportato è quello che ritengo rilevante al fine di rispondere alla tua domanda, Torvalds ha fatto molto più rant contro il C++ e parte delle cose che ha scritto sono rilevanti solo per il genere di programmi che fa lui (kernel e dintorni). In ogni caso ti ho messo li anche il link originale.

In altre parole: scrivere in C++ usando un sacco di new/delete, raw pointers, arrays e cose di questo tipo, ti porta ad avere un codice che fa schifo sia ai programmatori C++ che ai programmatori C. In alcuni casi però non vuoi fare affidamento sulle astrazioni che wrappano questi costrutti, ma allora tanto vale rinunciare a qualche altra features e scrivere un buon codice in C invece che un pessimo codice in C++.

Se non sei ancora pratico di programmazione, posso provare farti capire il mio discorso in questo modo.
il C++ è una penna a 6 colori, grossa da impugnare e quando esce il nuovo modello con il settimo colore, dovrai tenerti aggiornato. Il C invece è una normale bic, un solo colore e identica a quella che usava tuo nonno. Adesso immaginati di poter usare una sola penna. La penna a 6 colori ti permette di avere tutto più ordinato, ma spesso ti chiederai "qual'è il colore più adatto per scrivere questa parte?" (è difficile da usare pienamente e in modo appropriato). Se vuoi scrivere solo in blu e in rosso, probabilmente ti conviene fare qualche sacrificio e scrivere solo in blu piuttosto che dover avere a che fare con la scomodità di una penna a 6 colori. Ma in ogni caso, mentre le usi, ti sogneresti di avere tra le mani una bella stilografica dorata e con cartuccia intercambiabile (perché sia il C che il C++ sono tutt'altro che perfetti).
Nota: è solo un paragone metaforico, quindi non dargli troppa importanza.

In ogni caso, quando si parla di C vs C++, c'è sempre un sacco di gente che pensa che il C++ fa schifo e bisognerebbe evitarlo (vedi Torvalds) e altrettante persone che pensano che sia perfetto o che non ci sia alcuna ragione di utilizzare il C quando esiste il C++. È molto facile dare ragioni a questi ultimi, io stesso se dovessi iniziare un progetto e fossi indeciso tra questi due linguaggi, probabilmente sceglierei il C++, però spesso sarebbe meglio fare qualche considerazione in più prima di saltare a conclusioni affrettate.

Il C++ non è sempre meglio, anzi... personalmente condivido in pieno la citazione di Torvalds che ho riportato (il messaggio originale è molto meno condivisibile però).
 
"l'exception handling di C++ è uno scandalo" ovviamente è una affermazione di spettanza dello sviluppo di kernel.
Eh si... esattamente quel che dicevo prima, gran parte delle affermazioni che fa hanno senso solo se sviluppi un kernel. Il punto è che il kernel di un sistema operativo è un progetto di nicchia e non rappresenta assolutamente ciò che il programmatore medio ha interesse nello sviluppare. Di conseguenza, gran parte delle sue affermazioni non hanno alcun valore nel nostro contesto. La parte che ho scelto di riportare è quella che mi sembrava ragionevole e condivisibile per una domanda molto più generica rispetto a quella a cui lui risponde.

C'è bisogno, secondo me, di una rigorosa, severa e coraggiosa pulizia.
Eh... in realtà per il C++ non c'è bisogno proprio di niente. Sarà brutto quanto ti pare, ma è già il linguaggio principe per i progetti che richiedono performance o operazioni low level. Non è secondo a nessuno e se proprio bisogna dare consigli a qualcuno, bisognerebbe darli ai linguaggi che tentano di rimpiazzarlo. Con il C++ stanno già facendo quel che è necessario per non farlo diventare obsoleto.

E' assurdo che ancora per la gestione della memoria ci siano molte opzioni e soprattutto che ancora possa essere gestito tutto alla C-style, puntatori e tutto compreso. Naturalmente questo utilizzo è sconsigliato e deprecato, e allora perché continuare a permetterlo?
Come ho scritto nell'open post: la parola d'ordine è retrocompatibilità. In Python la codebase media è nell'ordine delle centinaia di righe di codice, con python3 (2008) hanno rotto la retrocompatibilità e 9 anni dopo abbiamo ancora due versioni di python mantenute in parallelo. In C++ la codebase media è nell'ordine delle migliaia di linee di codice, i cambiamenti da fare sarebbero più radicali e fare ciò che è stato fatto con python sarebbe del tutto insostenibile (e anche poco saggio).

Inoltre, per come la vedo io, il sistema di gestione della memoria non è una di quelle cose che rimuoverei. Ma questo è un altro discorso.
 
La sintassi non è cosa da poco, se hai regole strette sei obbligato a scrivere buon codice. Né il C e (soprattutto) né il C++ sono dei bei linguaggi da questo punto di vista, però se vuoi lavorare low level non hai grandi alternative. Negli ultimi anni stanno uscendo dei linguaggi che puntano a rimpiazzarli entrambi, ma attualmente sono troppo acerbi e non sufficientemente utilizzati.

Il C++ è il linguaggio più utilizzato in tutti i grandi progetti che richiedono molta performance (eg. rendering engines, DBMS, compilatori) mentre il C è il linguaggio più utilizzato per i progetti dove si lavora veramente low level (eg. kernel dei sistemi operativi, drivers, applicazioni embedded, ecc...). Poi molte volte si sceglie in base alla propria filosofia di pensiero: la JVM è scritta in C++, l'interprete di python è scritto in C, le Qt sono scritte in C++, le GTK sono scritte in C++, ecc...
Spesso è meglio partire fin da subito con un linguaggio che ti pone qualche limite in più invece che scendere a compromessi sulle features da utilizzare.

I vantaggi di usare il C++ invece del C direi che sono abbastanza ovvi: come ho già scritto nel open post, il C++ ha molte features in più ed è quasi interamente un superset del C. Se stai iniziando un nuovo progetto difficilmente sarai tentato dallo scegliere il C, ma allora perché c'è ancora tanta gente che lo usa ugualmente? È meno ovvio da capire, soprattutto per i neo-programmatori, ma spesso avere troppe features ti porta ad avere grandi problemi. A tal proposito ti cito un famoso post di Torvalds:


In altre parole: scrivere in C++ usando un sacco di new/delete, raw pointers, arrays e cose di questo tipo, ti porta ad avere un codice che fa schifo sia ai programmatori C++ che ai programmatori C. In alcuni casi però non vuoi fare affidamento sulle astrazioni che wrappano questi costrutti, ma allora tanto vale rinunciare a qualche altra features e scrivere un buon codice in C invece che un pessimo codice in C++.

Se non sei ancora pratico di programmazione, posso provare farti capire il mio discorso in questo modo.
il C++ è una penna a 6 colori, grossa da impugnare e quando esce il nuovo modello con il settimo colore, dovrai tenerti aggiornato. Il C invece è una normale bic, un solo colore e identica a quella che usava tuo nonno. Adesso immaginati di poter usare una sola penna. La penna a 6 colori ti permette di avere tutto più ordinato, ma spesso ti chiederai "qual'è il colore più adatto per scrivere questa parte?" (è difficile da usare pienamente e in modo appropriato). Se vuoi scrivere solo in blu e in rosso, probabilmente ti conviene fare qualche sacrificio e scrivere solo in blu piuttosto che dover avere a che fare con la scomodità di una penna a 6 colori. Ma in ogni caso, mentre le usi, ti sogneresti di avere tra le mani una bella stilografica dorata e con cartuccia intercambiabile (perché sia il C che il C++ sono tutt'altro che perfetti).
Nota: è solo un paragone metaforico, quindi non dargli troppa importanza.

In ogni caso, quando si parla di C vs C++, c'è sempre un sacco di gente che pensa che il C++ fa schifo e bisognerebbe evitarlo (vedi Torvalds) e altrettante persone che pensano che sia perfetto o che non ci sia alcuna ragione di utilizzare il C quando esiste il C++. È molto facile dare ragioni a questi ultimi, io stesso se dovessi iniziare un progetto e fossi indeciso tra questi due linguaggi, probabilmente sceglierei il C++, però spesso sarebbe meglio fare qualche considerazione in più prima di saltare a conclusioni affrettate.

Il C++ non è sempre meglio, anzi... personalmente condivido in pieno la citazione di Torvalds che ho riportato (il messaggio originale è molto meno condivisibile però).
Secondo me Torvalds ha ragione, il C è molto più snello e semplice; il C++ è una oscenità. Specialmente quando si tratta di scrivere un kernel: l'exception handling di C++ è uno scandalo, e se lo è anche per te e sai che non lo userai, perchè utilizzare un linguaggio che te lo fornisce, quando puoi utilizzare un linguaggio più semplice che te lo priva?

A Microsoft Corporation non piace questo elemento.
 
Non posso più modificare l'open post, ma segnalo che il link da cui si può scaricare la versione aggiornata di MinGW-w64 (windows) è winlibs.com (ringrazio @CrazyMonk per aver provato). Sul sito ufficiale le versioni precompilate non sono molto aggiornate. In alternativa si può usare MYSYS2 o Cygwin che contengono MinGW-w64, ma sono più vicini ad essere qualcosa in stile WSL. Personalmente consiglio MinGW-w64 da winlibs per chi vuole un installazione minimale e MYSYS2 per chi vuole un'esperienza unix-like pur compilando eseguibili per windows (a differenza di WSL), altrimenti sono ancora validi gli IDE segnalati nell'open post.
 
  • Mi piace
Reazioni: 0xbro e --- Ra ---
@St3ve alla fine hai letto il mio messaggio?
Sì, ho letto. Però non penso che valga la pena di aggiungere quell'alternativa perché sebbene possa essere un buon metodo per mettere in pausa il programma ("premi ctrl+z per chiudere"), non è quello che normalmente un utente vorrebbe fare. Io cercavo semplicemente un modo per emulare il system("pause").

A questo punto mi hai fatto venire in mente che potrei aggiungere una domanda del tipo "l'input non funziona correttamente" (rispolvererò qualche thread passato per trovare un nome un po' più azzeccato) dove spiego un po' meglio questo problema. Alla fine è una domanda frequente pure questa...
Accorcio un po' la risposta a "quando avvio il programma non vedo niente" e dedico un punto tutto suo al flush del buffer stdin.

Appena fixxeranno il problema di Sucuri ci metto mano.
 
  • Mi piace
Reazioni: srsly
Aggiornato.

Mi sono accorto di aver fatto casino con la grammatica (passo da singolare a plurale da una frase all'altra), ma sticazzi... immagino che si capisca comunque. Era inevitabile che con le modifiche avrei fatto casino, magari prima o poi sistemerò anche questo.
 
  • Mi piace
Reazioni: srsly
Ultima modifica:
Apposto, dopo leggo e ti faccio sapere
Mi sono accorto di aver fatto casino con la grammatica (passo da singolare a plurale da una frase all'altra), ma sticazzi... immagino che si capisca comunque
ma fregatene xd

Edit: per me va bene così ;)
 
  • Mi piace
Reazioni: St3ve
La sintassi non è cosa da poco, se hai regole strette sei obbligato a scrivere buon codice. Né il C e (soprattutto) né il C++ sono dei bei linguaggi da questo punto di vista, però se vuoi lavorare low level non hai grandi alternative. Negli ultimi anni stanno uscendo dei linguaggi che puntano a rimpiazzarli entrambi, ma attualmente sono troppo acerbi e non sufficientemente utilizzati.

Il C++ è il linguaggio più utilizzato in tutti i grandi progetti che richiedono molta performance (eg. rendering engines, DBMS, compilatori) mentre il C è il linguaggio più utilizzato per i progetti dove si lavora veramente low level (eg. kernel dei sistemi operativi, drivers, applicazioni embedded, ecc...). Poi molte volte si sceglie in base alla propria filosofia di pensiero: la JVM è scritta in C++, l'interprete di python è scritto in C, le Qt sono scritte in C++, le GTK sono scritte in C++, ecc...
Spesso è meglio partire fin da subito con un linguaggio che ti pone qualche limite in più invece che scendere a compromessi sulle features da utilizzare.

I vantaggi di usare il C++ invece del C direi che sono abbastanza ovvi: come ho già scritto nel open post, il C++ ha molte features in più ed è quasi interamente un superset del C. Se stai iniziando un nuovo progetto difficilmente sarai tentato dallo scegliere il C, ma allora perché c'è ancora tanta gente che lo usa ugualmente? È meno ovvio da capire, soprattutto per i neo-programmatori, ma spesso avere troppe features ti porta ad avere grandi problemi. A tal proposito ti cito un famoso post di Torvalds:


In altre parole: scrivere in C++ usando un sacco di new/delete, raw pointers, arrays e cose di questo tipo, ti porta ad avere un codice che fa schifo sia ai programmatori C++ che ai programmatori C. In alcuni casi però non vuoi fare affidamento sulle astrazioni che wrappano questi costrutti, ma allora tanto vale rinunciare a qualche altra features e scrivere un buon codice in C invece che un pessimo codice in C++.

Se non sei ancora pratico di programmazione, posso provare farti capire il mio discorso in questo modo.
il C++ è una penna a 6 colori, grossa da impugnare e quando esce il nuovo modello con il settimo colore, dovrai tenerti aggiornato. Il C invece è una normale bic, un solo colore e identica a quella che usava tuo nonno. Adesso immaginati di poter usare una sola penna. La penna a 6 colori ti permette di avere tutto più ordinato, ma spesso ti chiederai "qual'è il colore più adatto per scrivere questa parte?" (è difficile da usare pienamente e in modo appropriato). Se vuoi scrivere solo in blu e in rosso, probabilmente ti conviene fare qualche sacrificio e scrivere solo in blu piuttosto che dover avere a che fare con la scomodità di una penna a 6 colori. Ma in ogni caso, mentre le usi, ti sogneresti di avere tra le mani una bella stilografica dorata e con cartuccia intercambiabile (perché sia il C che il C++ sono tutt'altro che perfetti).
Nota: è solo un paragone metaforico, quindi non dargli troppa importanza.

In ogni caso, quando si parla di C vs C++, c'è sempre un sacco di gente che pensa che il C++ fa schifo e bisognerebbe evitarlo (vedi Torvalds) e altrettante persone che pensano che sia perfetto o che non ci sia alcuna ragione di utilizzare il C quando esiste il C++. È molto facile dare ragioni a questi ultimi, io stesso se dovessi iniziare un progetto e fossi indeciso tra questi due linguaggi, probabilmente sceglierei il C++, però spesso sarebbe meglio fare qualche considerazione in più prima di saltare a conclusioni affrettate.

Il C++ non è sempre meglio, anzi... personalmente condivido in pieno la citazione di Torvalds che ho riportato (il messaggio originale è molto meno condivisibile però).

Grazie infinite, mi hai dato una risposta veramente esauriente :D
 
Personalmente preferisco quasi sempre programmare in C rispetto al C++, e nei casi in cui non mi è necessario usare C preferisco usare qualcosa di completamente differente (insomma evito C++ per quanto possibile, ma questi sono gusti personali).
Una delle motivazioni che hanno formato questo gusto è la mancanza di coraggio che secondo me al momento c'è per quel che riguarda lo sviluppo del C++.

Negli anni si sono aggiunti standard su standard, molte cose sono state deprecate, alcune rimosse (basti vedere gli standard C++11, 14 e 17). La mancanza di coraggio dov'è?
E' il rimanere legati, vuoi per retrocompatibilità e tante altre motivazioni, alle feature di C.
Al momento C++ è veramente un ammasso confusionario di sintassi enorme, ci sono veramente 10 modi differenti per fare qualsiasi cosa, di questi modi però 3 sono stilisticamente considerati balordi, 4 sono deprecati, 1 è da folli e 2 sono accettati (ovviamente è un esempio).
Ma insomma mi è capitato spesso lavorando in progetti grossi di perdere più tempo per rimanere aggiornato sullo standard e su quale sarebbe stato il modo migliore per fare una determinata cosa che altro.

Non è possibile dopo 40 anni avere un linguaggio che non ha tagliato praticamente nulla, e uno dei problemi che dice Torvalds deriva proprio da questo, molti programmatori C++ scrivono completi aborti di codice, e la colpa (o almeno parte della colpa) è dello stesso linguaggio che permette questi scempi.
Scempi giustificati perché sinceramente è abbastanza fastidioso ogni volta doversi andare a controllare lo standard attuale e ricontrollare se cose scritte 2 anni fa sono ancora considerate decenti oppure al momento sono deprecate.
E non dico che non devono esserci cose deprecate, dico che dopo 40 anni molta roba che è deprecata debba smettere di essere supportata, ed è questo il coraggio che secondo me manca.

E' assurdo che ancora per la gestione della memoria ci siano molte opzioni e soprattutto che ancora possa essere gestito tutto alla C-style, puntatori e tutto compreso. Naturalmente questo utilizzo è sconsigliato e deprecato, e allora perché continuare a permetterlo?
All'inizio aveva senso, dopo 40 anni non lo so.

C'è bisogno, secondo me, di una rigorosa, severa e coraggiosa pulizia.
 
  • Mi piace
Reazioni: SpeedJack
Sì, però tieni conto che ho volutamente citato solo un pezzo del suo messaggio.
Lui lascia intendere STL e Boost non sono portable e non sono stabili, ma è oggettivamente falso in un contesto puramente generico. È un'assunzione valida quasi solo se si parla di programmare il kernel di un sistema operativo, ma per qualsiasi altra cosa sia STL che Boost sono veramente lo state of the art. Per git ha scelto il C perché "efficiency was a primary objective" e anche il C++ era troppo high level, ma mercurial (il diretto concorrente di git) è scritto in python. Anche "C++ compilers are not trustworthy" è una frase decisamente azzardata: magari non lo erano nel '92, ma 25 anni dopo mi sembra una frase eccessiva anche se ti metti a programmare un kernel.
Per GCC hanno scelto di passare dal C al C++ (link) e già questo fa riflettere.

Personalmente non sono un fan dell'exception handling, pochi linguaggi hanno questo sistema esposto nel modo in cui piace a me, quindi non sarò io a difendere questo sistema, però "l'exception handling di C++ è uno scandalo" è una frase che va motivata. Sia STL che Boost fanno un uso sensato delle eccezioni e mi fa solo piacere sapere che non sono over-utilizzate come in Java.

Molti dei ragionamenti che fa sono relativi a quello programma lui, ma un kernel non è il tipico progetto che il programmatore medio si mette a scrivere. Quindi buona parte del ragionamento fatto da Torvalds non è rilevante per la domanda fatta da C3n21.
"l'exception handling di C++ è uno scandalo" ovviamente è una affermazione di spettanza dello sviluppo di kernel. Le eccezioni potrebbero non essere del tutto acconce per lo sviluppo di kernel perchè la sincronizzazione può essere una "mollezza" in più in quanto più difficile da garantire. L'opposto per gli error code in C.
Anche impiegare la proficua feature RAII di C++, una delle più ricche del linguaggio, potrebbe essere deleteria in un kernel. http://harmful.cat-v.org/software/c++/linus:
- the whole C++ exception handling thing is fundamentally broken. It's
_especially_ broken for kernels.
- any compiler or language that likes to hide things like memory
allocations behind your back just isn't a good choice for a kernel.

- you can write object-oriented code (useful for filesystems etc) in C,
_without_ the crap that is C++.
nel secondo punto, Torvalds ha palesato che l'automazione (più che hiding) di operazioni cruciali potrebbe comportare pessimi avvenimenti. Difatti gli sviluppatori del kernel di solito non prediligono queste caratteristiche.
 
  • Mi piace
Reazioni: DanyDollaro
Ultima modifica da un moderatore:
hey St3ve, sei un ragazzo intelligente, allora :D
Se c'è qualche domanda che ti piacerebbe vedere in questa lista o se parte di quello che ho detto non ti è chiaro o ti sembra sbagliato, segnalalo nei commenti e provvedo a fixxare quel che serve. Stessa cosa se vuoi qualche approfondimento o cose del genere.
Attualmente non ho riletto, se trovate qualche errore avvisate.
Sono d'accordo con quello che consigli
Un'alternativa per il buffer STDIN:
C:
freopen(NULL, "r", stdin);
Per "cosa c'è di migliore" è solo una questione soggettiva, ma mi piace pure quest'alternativa per meno codice e potenzialmente efficiente, naturalmente a seconda dell'implementazione di freopen()
Beh, il while-loop nel codice C genera un nuovo stack frame che ha bisogno di essere gestito in ogni iterazione. freopen() oltre quello, può pulire anche il buffer STDIN in un modo anche più "efficiente"
se vuoi qua c'è tutto http://pubs.opengroup.org/onlinepubs/000095399/functions/freopen.html
bravo per il thread!
 
Ultima modifica:
hey St3ve, sei un ragazzo intelligente, allora :D

Sono d'accordo con quello che consigli
Un'alternativa per il buffer STDIN:
Codice:
freopen(NULL, "r", stdin);
Per "cosa c'è di migliore" è solo una questione soggettiva, ma mi piace pure quest'alternativa per meno codice e potenzialmente efficiente, naturalmente a seconda dell'implementazione di freopen()
Beh, il while-loop nel codice C genera un nuovo stack frame che ha bisogno di essere gestito in ogni iterazione. freopen() oltre quello, può pulire anche il buffer STDIN in un modo anche più "efficiente"
se vuoi qua c'è tutto http://pubs.opengroup.org/onlinepubs/000095399/functions/freopen.html
bravo per il thread!
Il difetto di freopen è che alloca memoria nello heap (almeno nell'implementazione della glibc, debugger alla mano). Non ci sono memory leaks perché è tutta roba che gestisce internamente, però la rallenta di molto.
Un altra possibilità sarebbe quella di fare giochetti con la scanf, tipo scanf("%*[^\n]\n"); ma l'ho voluta segnalare sia perché reputo la versione con il while migliore, sia per non complicare le cose.

Comunque sia, grazie per il contributo. Mi piacerebbe aggiungere un link al tuo post nell'OP, ma l'errore di Sucuri Website Firewall ultimamente mi perseguita. In ogni singolo post faccio fatica a citare qualcosa e ora non riesco a fare modifiche al post iniziale. Appena ne avrò la possibilità, farò le dovute modifiche.
Qualcuno dello staff sa qualcosa a riguardo? Questo errore era già stato segnalato tempo fa, ora è peggiorato drasticamente...
 
Comunque sia, grazie per il contributo. Mi piacerebbe aggiungere un link al tuo post nell'OP, ma l'errore di Sucuri Website Firewall ultimamente mi perseguita. In ogni singolo post faccio fatica a citare qualcosa e ora non riesco a fare modifiche al post iniziale. Appena ne avrò la possibilità, farò le dovute modifiche.
Qualcuno dello staff sa qualcosa a riguardo? Questo errore era già stato segnalato tempo fa, ora è peggiorato drasticamente...
Per i codici intendi?
Sucuri ci serve perché ci difende da attacchi XSS, SQLi e altri - sappiamo benissimo che è fastidioso ma dobbiamo tenerlo.
Ad ogni modo il problema è che Sucuri prende alcuni particolari pattern di codici come tentativi di attacco - quando ti si presenta il messaggio di Sucuri, mandami il codice che provavi ad inserire (ancora meglio se riesci a estrarre l'esatta riga di codice che crea problemi - di solito è solo una riga) all'indirizzo speedjack (at) inforge (dot) org (occhio al .org - non è .net). Io provvederò a segnalarlo a murdercode che di solito nel giro di pochi giorni lo risolve. (anche se non rispondo, le mail le leggo tutte).
 
Ultima modifica da un moderatore:
più che altro non mi venivano in mente altre alternative
Non ci sono memory leaks perché è tutta roba che gestisce internamente, però la rallenta di molto.
fai una cosa, lascialo così, in caso poi inserisci nell'@OP questa alternativa sempre elencando i vantaggi e svantaggi

leggendo l'altro pezzo di codice
C++:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
Da http://en.cppreference.com/w/cpp/io/basic_istream/ignore:
Extracts and discards characters from the input stream until and including delim. ignorebehaves as an UnformattedInputFunction. After constructing and checking the sentry object, it extracts characters from the stream and discards them until any one of the following conditions occurs:
  • count characters were extracted. This test is disabled in the special case when countequals std::numeric_limits<std::streamsize>::max()

  • end of file conditions occurs in the input sequence, in which case the function calls setstate(eofbit)

  • the next available character c in the input sequence is delim, as determined byTraits::eq_int_type(Traits::to_int_type(c), delim). The delimiter character is extracted and discarded. This test is disabled if delim is Traits::eof()
Se cerchi di cancellare l'intero buffer, considera di pulire fino a end-of-file invece di end-of-line
Considera pure di pulire lo stato dello stream usando std::basic_ios::clear().
std::cin.get();
Considera pure di usare la funzionalità breakpoint dei debuggers se vuoi prevenire una applicazione dalla chiusura attraverso un IDE.
return 0;
Come è delineato negli standard C99+ e C++, non si dovrebbe fare esplicitamente return 0; da main()
Comunque, se decidi di returnare esplicitamente da main(), considera di usare gli standard cross-platform di EXIT_SUCCESS e EXIT_FAILURE.
Non ci sono comunque imperfezioni

Mi piacerebbe aggiungere un link al tuo post nell'OP, ma l'errore di Sucuri Website Firewall ultimamente mi perseguita. In ogni singolo post faccio fatica a citare qualcosa e ora non riesco a fare modifiche al post iniziale.
Succede anche a me alcune volte ma non sempre. Usi il vecchio tema dark per caso? Forse quello sarebbe uno che influisce sul problema @SpeedJack
 
Ultima modifica da un moderatore:
Se cerchi di cancellare l'intero buffer, considera di pulire fino a end-of-file invece di end-of-line
End of file è troppo, ho provato e continua a mangiarsi roba perché non raggiunge mai l'end of file (stessa cosa con '\0'). Se vuoi farti un'idea prova tu stesso:
C++:
#include <iostream>
#include <limits>
#include <cstdio>

void foo()
{
    int c;

    std::cout << "iserisci un numero: ";
    c = std::getchar();

    std::cout << "hai inserito: " << c << "\n";

    // std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // questo è ok
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), std::char_traits<char>::eof()); // questo no
}

int main()
{
    foo();
    foo();
    foo();

    return 0;
}


Considera pure di pulire lo stato dello stream usando std::basic_ios::clear().
Si, questo può essere decisamente utile. Aggiungo, thanks.


Come è delineato negli standard C99+ e C++, non si dovrebbe fare esplicitamente return 0; da main()
Preferisco mantenere il return 0 perché si trova quasi sempre scritto sotto questa forma. Il return 0 implicito credo che sia stato introdotto con il C99 (e con il C++ in generale). Nel pdf dello standard C11 usano return 0 per uscire dal main nei loro esempi, quando parlano di EXIT_SUCCESS e EXIT_FAILURE citano funzione exit.
Ovviamente sono sottiliezze da niente, ma per queste ragioni preferisco lasciarlo così.


@SpeedJack: hai presente che nel pm ti avevo segnalato che con chrome il problema sembrava risolto? Ecco, no :asd:
Diciamo che con chrome il problema è apparentemente meno grave (anche perché sto appena provando), ma non riesco ancora a toccare il primo post.
 
End of file è troppo, ho provato e continua a mangiarsi roba perché non raggiunge mai l'end of file (stessa cosa con '\0'). Se vuoi farti un'idea prova tu stesso:
Codice:
#include <iostream>
#include <limits>
#include <cstdio>

void foo()
{
    int c;

    std::cout << "iserisci un numero: ";
    c = std::getchar();

    std::cout << "hai inserito: " << c << "\n";

    // std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // questo è ok
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), std::char_traits<char>::eof()); // questo no
}

int main()
{
    foo();
    foo();
    foo();

    return 0;
}
St3ve, std::cin non raggiungerà mai std::eof a meno che CTRL-D o CTRL-Z sono dati come input (dipende dall'OS).
Questi input speciali imposteranno la flag eof di std::cin, ma come già detto, dipende dal sistema operativo.
 
[COLOR=rgb(33, 80, 97)]@SpeedJack[/COLOR]: hai presente che nel pm ti avevo segnalato che con chrome il problema sembrava risolto? Ecco, no :asd:
Diciamo che con chrome il problema è apparentemente meno grave (anche perché sto appena provando), ma non riesco ancora a toccare il primo post.
murder ha risposto, ha chiesto che apri un Ticket nel Reparto Tecnico riportando i problemi che incontri e incollando anche i messaggi di Sucuri e lui vedrà di risolverteli :3
 
Salve a tutti, da ignorante mi permettete una domanda?

Quanto possono centrare conoscenze matematiche, o relative all'ambito elettronico etc. con la programmazione?