Guida [GUIDA] Cose da evitare in C/C++

SpeedJack

Sviluppatore
Amministratore
18 Febbraio 2010
5,788
74
3,825
1,413
Ultima modifica:
38dffbf8bd323587aaecd19a9f51243e.png
Qualsiasi programmatore sa bene che il C e il C++ sono linguaggi nativi unsafe. In questi linguaggi non c'è nessun controllo su quello che il programmatore ha scritto. Questo permette al programmatore di non essere limitato entro strette regole di programmazione. Però programmatori inesperti di questi linguaggi possono inciampare in "piccoli errori" che possono compromettere diversi aspetti del programma (e, a volte, anche del sistema operativo in cui è eseguito):
  • Il suo corretto funzionamento o quello di un altro programma;
  • Le sue prestazioni e il corretto utilizzo delle risorse;
  • La sua stabilità, quella di un altro programma o del sistema operativo;
  • La sicurezza del sistema operativo.
Programmi C/C++ non scritti correttamente possono anche causare dei Blue-Screen-Of-Death (BSOD) portando in crash l'intero sistema operativo; oppure possono presentare falle di sicurezza come buffer overflow o format string overflow che possono permettere a hacker e malintenzionati di prendere il controllo dell'intero sistema eseguendo del codice remoto (Remote Code Execution, RCE).

Per questi motivi, e per tanti altri, è importante che chiunque utilizzi il C o il C++ conosca bene le regole che spiegherò in questa guida. In tal modo potranno essere evitati gli errori più comuni dei programmatori novizi che a volte possono anche portare a gravi danni: piccoli programmini scritti da programmatori alle prime armi possono facilmente trasformarsi in pericolose falle di sicurezza utilizzabili dagli hacker.



1) void main()

attention_transparent.gifPuò compromettere: il corretto funzionamento di altri programmi; la stabilità del programma; la stabilità di altri programmi; la stabilità del sistema operativo.

Spesso si trovano programmi che utilizzano void main() per definire l'entry-point del proprio programma. In realtà main() è una funzione di tipo int, e deve essere definita così (lo chiede anche lo Standard ANSI C). Vediamo perché e cosa succede se invece definiamo main() come void.

Lasciamo un attimo stare il main (lo riprendiamo dopo) e prendiamo ad esempio questo codice (che ci servirà a capire):
az8fJ.PNG
Questo codice fa una cosa banale: cerca di calcolare la radice quadrata di 144. Però, se provate ad eseguire il codice, il risultato sarà senz'altro qualcosa di sbagliato:
az8it.PNG
Perché questo? perché la funzione sqrt ritorna normalmente un valore double. Noi ci stiamo comportando invece come se ritornasse un valore int: infatti abbiamo definito sqrt come int e vogliamo stampare su schermo il suo valore di ritorno utilizzando %d che si aspetta di trovare un valore int. Questo provoca un piccolo effetto collaterale: le macchine utilizzano un particolare registro per contenere i valori di ritorno delle funzioni intere (EAX) e un particolare registro per contenere i valori di ritorno delle funzioni che ritornano valori in virgola mobile. Quindi, possono succedere diverse cose: sqrt scrive il suo valore double nel registro per i valori in virgola mobile, però il nostro codice legge il valore contenuto nel registro EAX (quello dei valori int) e quindi legge un numero sbagliato; oppure, anche se non si verificasse questo problema (ad esempio, se sia i numeri interi che quelli in virgola mobile vengono passati utilizzando lo stesso registro), il nostro codice andrebbe ad interpretare un valore double come int, fornendo così un risultato sbagliato.
Inoltre ci sono altri effetti negativi: questi errori possono anche sbilanciare lo stack (se una viene inserito un valore di dimensione double nello stack e poi viene tolto un valore di dimensione int alcuni byte resteranno nello stack).

Con il main è la stessa cosa. Si può immaginare che colui che avvia il programma (un altro programma o il sistema operativo) utilizzi un codice tipo questo:
az8hh.PNG
Questo codice si aspetta che il main ritorni un valore int, invece main è definito come void! Per questo motivo potrebbe rendere il sistema instabile sbilanciando lo stack e portandolo al crash.
Oppure con void la funzione main ritornerà un valore random. Di solito questo non è un problema ma potrebbe diventarlo: se ad esempio il valore di ritorno di main supera il valore di Sys$RCLimit (che è il valore massimo che può avere un valore di ritorno) il sistema operativo lancerà un errore; oppure se il valore di ritorno di main a un valore diverso da 0, un programma o uno script che fa uso di quel programma potrebbe interpretare quel valore di ritorno come un codice errore e quindi comportarsi in modo anomalo.

Quindi, in sostanza, void main() è da evitare:
  • Perché lo Standard ANSI C dice che non va usato;
  • Perché può sbilanciare lo stack minando la stabilità del sistema operativo o di altri programmi;
  • Perché può compromettere il corretto funzionamento di altri programmi ritornando valori random che possono assumere significati non previsti.
main() deve quindi essere definita con:
int main()
oppure:
int main(void)
oppure:
int main(int argc, char **argv)



2) system("pause")

attention_transparent.gifPuò compromettere: le prestazioni del programma.

system("pause") è largamente utilizzato per mettere in pausa il programma in attesa della pressione di un tasto da parte dell'utente. Funziona benissimo, ma ha un difetto: costringe a fare una chiamata alle funzioni interne del sistema operativo.
Quando system("pause") viene chiamato, in breve, succede questo:
  1. Il processo del programma viene sospeso
  2. Viene chiamato il sistema operativo
  3. Il sistema operativo deve cercare il comando pause
  4. Il sistema operativo deve allocare la memoria necessaria ad utilizzare il comando
  5. Il comando viene eseguito (e il programma si mette in attesa della pressione di un tasto)
  6. La memoria viene deallocata
  7. Il sistema operativo restituisce il controllo al processo del programma
  8. Il processo del programma riparte
Chiaramente: tutto questo è molto laborioso e fa perdere un sacco di tempo inutile al programma soltanto per mettersi in pausa.
Inoltre, per utilizzare system("pause"), deve essere inclusa la libreria stdlib.h che magari si poteva evitare.
Ancora: system("pause") può funzionare solo su sistemi Windows (e anche DOS) mentre non funziona su Linux.

Quindi, in sostanza, system("pause") è da evitare:
  • Perché aggiunge lavoro inutile al programma rendendolo più pesante in esecuzione;
  • Perché obbliga a includere la libreria stdlib.h che spesso si può evitare;
  • Perché funziona solo su sistemi Microsoft Corporation.

Come alternativa a system("pause") possiamo utilizzare qualsiasi funzione che prende informazioni da stdin.
Ad esempio c'è getch(). Questa funzione è però definita in conio.h e per questo motivo è presente solo in alcuni compilatori (Borland, MSVC++, ...). Perciò, di solito, si preferisce evitare anche getch().
Di gran lunga preferibile è invece getchar(). Questa funzione si trova in tutte le implementazioni di ANSI C. Una volta che il programma è compilato, si tratta semplicemente di un salto a una funzione in quanto getchar() viene compilata all'interno del programma (a differenza di system("pause") che è sempre esterna).
In C++ invece è preferibile utilizzare cin.get(). Questa funzione è l'equivalente C++ di getchar().
L'alternativa finale, se si vuole mettere in pausa il programma solo perché non si chiuda alla fine dell'esecuzione, è quella di avviare il programma da console invece che facendo doppio click sull'eseguibile (di fatto, le applicazioni console, sono state ideate proprio affinché vengano avviate da console).



3) ................................


99) Fonti

Steve Summit, Articolo del 23 Agosto 1996, http://www.eskimo.com/~scs/readings/voidmain.960823.html




TOPIC IN AGGIORNAMENTO!!! .....
Se avete altre cose da aggiungere a questa lista, potete scriverle in topic. Sono già in programma:
-scanf()
-gets()
-feof()
-le varie funzioni su stringa con i possibili buffer overflow
-malloc() senza free()
Se avete in mente qualcosa che non compare in questa lista, fatemelo sapere e lo aggiungerò in futuro.
 
Aggiungerei una cosa, anche se non si tratta di sicurezza(in realtà potrebbe comprometterla) ma più un notevole risparmio di bestemmie nel caso in cui non lo si sa.
Il C++ con la classe string sembra una figata, ma attenzione a scrivere le string in file binari! Se si ha una struct (o una classe) da riportare su file binario, onde evitare im*******menti vari in fase di lettura, evitare assolutamente diutilizzare campi quali "string nome", piuttosto sovradimensionare un array di char mediante ad esempio " char nome[10]"

Comunque il post è molto interessante, io aggiungerei di fare attenzione anche con le funzioni virtuali, ed utilizzarle solo quando realmente necessario. Magari se ho più tempo vedo di tradurre qualcosa e fare un paper sulla programmazione c\c++ avanzata, comprendente anche le possibili vulnerabilità che potrebbero verificarsi.
 
Ciao [MENTION=212442]vincent0x[/MENTION]

La ringrazio del contributo. Aggiungerò queste cose alla fine: prima mi occupo dei "problemi" del C (che, in fondo, può avere anche il C++) poi guarderò quelli relativi soltanto al C++.


Intanto ho aggiunto anche system("pause") (ma devo sempre finirlo)
 
Se decidessimo di non fare uso del system("pause") per le conseguenze citate da te in precedenza con cosa possiamo sostituire questo comando? È importante richiamare una pausa alla fine del comando per avviare l'exe.
Inoltre, il problema del system("pause") vale solo per questo determinato comando oppure per tutti i system?
 
Intanto partiamo dal presupposto che non si parla sempre di exe e poi esiste getchar e simili, ma penso che ci pensi lui ad aggiornarla correttamente...
 
Ryou come ho scritto sopra non ho ancora finito di scrivere su system("pause")...ci sono più metodi sostitutivi: getchar; cin.get; getch; ecc. e li aggiungerò appena posso.

Comunque vale per tutti i comandi system: ovviamente devono tutti richiamare il sistema operativo. Però in certi casi può anche avere senso: è uno spreco se si usa solamente per mettere in pausa un programma.

Sent from my GT-I9505 using Tapatalk
 
  • Mi piace
Reazioni: Ryou
se hai voglia aggiungi anche questi punti:
1) preferire le referenze ai puntatori quando possibile
2) se si usa una struct per salvare i dati letti da un dispositivo hardware controllare l'allineamento dei dati (spesso i compilatori ottimizzano i char con le int sui sistemi a 32 bit e ciò corrompe la lettura dati)
3) se si viene dal java evitare robe del tipo Oggetto var = Oggetto(param); ma chiamare direttamente il costruttore Oggetto var(param); (si recupera un piccolo overhead dovuto al copy-costructor)
4) non fidarsi mai dell'utente, leggere i dati in una stringa e poi eseguire un parsing della stessa (risparmierete molte madonne)
5) attenzione agli iteratori non sono altro che puntatori impacchettati
 
  • Mi piace
Reazioni: SpeedJack
Quello che dici non è affatto sbagliato, tuttavia ritengo (mio modesto parere) che la funzione system() non sia da trascurare in fase di apprendimento... il modo più semplice per imparare ad avere dimestichezza con lei e usarla con il "PAUSE", pratica che in programmi ad alto livello di ottimizzazione non va sicuramente attuata.

Il problema della portabilità può essere facilmente byepassato:

PHP:
#include <iostream>
#include <cstdlib>

#ifdef __linux__
 
   #define _pause system("read")

#elif _WIN32 || _WIN64

   #define _pause system("PAUSE")

#endif

tuttavia il system("pause") la possiamo considerare una buona pratica didattica...
Per il resto, quoto completamente
 
In realtà main() è una funzione di tipo int, e deve essere definita così (lo chiede anche lo Standard ANSI C).
Piccola precisazione: l'ANSI C consente anche il void main, dal primo standard ISO in poi è consentito solo se è implementation-defined (se il compilatore lo consente -- ovvero non è consentito), anche se si consiglia di definirlo come int. In C++ invece non è proprio ammesso.
Anche l'esempio di codice che hai riportato: è valido per il C, ma non è vero per il C++.

Anche lo sbilanciamento dello stack mi sembra un esempio un po' troppo estremo e poco realistico nei sistemi operativi moderni e il Sys$RCLimit credo che sia definito solo nelle architetture RISC, di fatto ti devi impegnare per far accadere questi problemi. Però vabbè... è verissimo che compromette l'esecuzione di altri prdogrammi (in particolare degli script, chi usa linux ne sa qualcosa) e comunque l'importante è far capire il concetto.


Il C++ con la classe string sembra una figata, ma attenzione a scrivere le string in file binari! Se si ha una struct (o una classe) da riportare su file binario, onde evitare im*******menti vari in fase di lettura, evitare assolutamente diutilizzare campi quali "string nome", piuttosto sovradimensionare un array di char mediante ad esempio " char nome[10]"
O più semplicemente puoi serializzare anche la lunghezza della stringa, 1 byte di overhead e dovresti aver problemi. Probabilmente esistono anche modi migliori per evitare anche quel byte in più, ho un paio di idee, ma bisognerebbe provarci.
Comunque questo consiglio vale per chiunque, non è solo un problema legato al C/C++, ma vale per qualsiasi altro linguaggio.


se hai voglia aggiungi anche questi punti:
1) preferire le referenze ai puntatori quando possibile
2) se si usa una struct per salvare i dati letti da un dispositivo hardware controllare l'allineamento dei dati (spesso i compilatori ottimizzano i char con le int sui sistemi a 32 bit e ciò corrompe la lettura dati)
3) se si viene dal java evitare robe del tipo Oggetto var = Oggetto(param); ma chiamare direttamente il costruttore Oggetto var(param); (si recupera un piccolo overhead dovuto al copy-costructor)
4) non fidarsi mai dell'utente, leggere i dati in una stringa e poi eseguire un parsing della stessa (risparmierete molte madonne)
5) attenzione agli iteratori non sono altro che puntatori impacchettati
Il punto 3 non è necessariamente vero nel nuovo standard (anche se è meglio seguire il tuo consiglio), i punti 2 e 4 aggiungo che pure questi problemi esistono per qualsiasi linguaggio e nel punto 5 non ho capito qual'è il problema.


Quello che dici non è affatto sbagliato, tuttavia ritengo (mio modesto parere) che la funzione system() non sia da trascurare in fase di apprendimento... il modo più semplice per imparare ad avere dimestichezza con lei e usarla con il "PAUSE", pratica che in programmi ad alto livello di ottimizzazione non va sicuramente attuata.

Il problema della portabilità può essere facilmente byepassato:

PHP:
#include <iostream>
#include <cstdlib>

#ifdef __linux__
 
   #define _pause system("read")

#elif _WIN32 || _WIN64

   #define _pause system("PAUSE")

#endif

tuttavia il system("pause") la possiamo considerare una buona pratica didattica...
Per il resto, quoto completamente
E sei sicuro al 100% che su windows e su linux system("pause") non mi vada ad eseguire il programma "pause" contenuto nella stessa directory dell'eseguibile? Non si può semplicemente assumere che questo programma non esista sul pc di qualcun altro.
E se su windows e su linux (e su mac) esegue effettivamente quello che tutti si aspettano (non lo so, non ho provato) non possiamo comunque dire che sul sistema operativo di pippo (o in una futura versione dell'os) questa cosa resti vera. In definitiva possiamo forse (*forse*) dire che quel codice funziona su windows e su linux, ma di sicuro non è portable al 100% come lo sarebbe se non si conoscesse quell'istruzione.
Senza contare che in 5 linee di codice non hai comunque tenuto in considerazione il mac (anche se credo che il numero di linee rimanga lo stesso), per implementare qualcosa che rimpiazzi il system("pause") senza utilizzare codici dipendenti dal sistema ti serviranno 3 righe al massimo.

A mio parere prima ci si dimentica che esiste e meglio è, non è buono nemmeno per scopi didattici: non si sta interpellando il sistema (oprazione costosa, anche se in questo caso interessa pochissimo) per eseguire qualcosa di difficile, lo richiami per una banalità.
 
Uh vedo che questa discussione interessa...
Grazie a @St3ve @Jacotsu e @Simur Birkoff per i loro contributi. Valuterò e inserirò anche i vostri contributi via via che vado avanti. Un po' ci vuole che devo anche verificarli (anche solo lo Standard ANSI è scritto in un PDF di 700 pagine e trovare quello che serve a volte è laborioso :\ ).
 
E sei sicuro al 100% che su windows e su linux system("pause") non mi vada ad eseguire il programma "pause" contenuto nella stessa directory dell'eseguibile? Non si può semplicemente assumere che questo programma non esista sul pc di qualcun altro.
E se su windows e su linux (e su mac) esegue effettivamente quello che tutti si aspettano (non lo so, non ho provato) non possiamo comunque dire che sul sistema operativo di pippo (o in una futura versione dell'os) questa cosa resti vera. In definitiva possiamo forse (*forse*) dire che quel codice funziona su windows e su linux, ma di sicuro non è portable al 100% come lo sarebbe se non si conoscesse quell'istruzione.
Senza contare che in 5 linee di codice non hai comunque tenuto in considerazione il mac (anche se credo che il numero di linee rimanga lo stesso), per implementare qualcosa che rimpiazzi il system("pause") senza utilizzare codici dipendenti dal sistema ti serviranno 3 righe al massimo.

A mio parere prima ci si dimentica che esiste e meglio è, non è buono nemmeno per scopi didattici: non si sta interpellando il sistema (oprazione costosa, anche se in questo caso interessa pochissimo) per eseguire qualcosa di difficile, lo richiami per una banalità.

Per il mac basta aggiungere due linee di codice... e così via per ogni altro OS.
Per il resto devo dire che hai ragione, soffre di qualche ambiguità. Possiamo assumere per vero il fatto che nel prossimo futuro pause.exe non verrà deprecato... verosimilmente!

ps: io sono d'accordo con ciò che dice SpeedJack e a ruota con ciò che dici tu... ritengo semplicemente che resta una possibilità importante quella di interagire così facilmente col sistema operativo, system() vuole solo fornirci la possibilità di richiamare un eseguibile in un altro.
Se sindachiamo su system("pause") allora posso essere in accordo... ma il problema non è "system()" ma "pause"
 
Per il mac basta aggiungere due linee di codice... e così via per ogni altro OS.
Per il resto devo dire che hai ragione, soffre di qualche ambiguità. Possiamo assumere per vero il fatto che nel prossimo futuro pause.exe non verrà deprecato... verosimilmente!

ps: io sono d'accordo con ciò che dice SpeedJack e a ruota con ciò che dici tu... ritengo semplicemente che resta una possibilità importante quella di interagire così facilmente col sistema operativo, system() vuole solo fornirci la possibilità di richiamare un eseguibile in un altro.
Se sindachiamo su system("pause") allora posso essere in accordo... ma il problema non è "system()" ma "pause"

Il problema grosso è con pause, read, cls, clear e per tutte quelle cose che puoi fare senza chiedere niente al sistema operativo.
Ma anche in generale l'uso di system è sconsigliabile: il programma non può sapere l'output del programma che esegue, il tuo programma si blocca fino al termine del comando che ha lanciato, non sai se si aprirà o meno una nuova shell, non sai se stai lanciando un programma valido o se il programma che stai lanciando è quello che ti aspetti, se fai uso delle variabili d'ambiente l'utente un malintenzionato potrebbe far danni, se lo avvii come amministratore (o con i privilegi di root) può avere risultati inaspettati (per linux vedi le note qui).
Una volta che chiami system quello che succede è fuori dal tuo controllo, se quel programma si comporta in modo anomalo sei fortunato se riesci ad accorgertene controllando il return value.

Sembra conveniente perché è definita dallo standard ed, escludendo porcate tipo pause dove non si hanno scuse per usarla, è più facile scrivere codice multipiattaforma, ma secondo me meno la si usa e meglio è. Se devi interagire con il sistema operativo è meglio usare quello che il sistema stesso ti mette a disposizione nelle sue librerie (che di fatto è quello che fa system), saranno meno user friendly, ma almeno sai bene quel che fai e hai la possibilità di gestire tutte le varie sfaccettature che potrebbero causare problemi.

Con questo non voglio dire che non vada mai usata, ma meno la si usa e meglio è: evitare di chiamare in causa il sistema operativo è la cosa migliore, se proprio non si può bisognerebbe prendersi delle precauzioni per assicurarsi che tutto fili liscio.

PS.
Il Mac è sempre UNIX-like, quindi probabilmente non serve aggiungere due linee di codice, basta un or con la costante (define) del Mac.


Un po' ci vuole che devo anche verificarli (anche solo lo Standard ANSI è scritto in un PDF di 700 pagine e trovare quello che serve a volte è laborioso :\ ).

Se ti riferisci a quello che avevo detto io riguardo il main, toh
http://pasteboard.co/1WOXxAky.png (non riesco a farla vedere con il tag apposta)
Non è riferito al void main (che effettivamente non è mai stato permesso se non con la clausola che ho specificato nel messaggio precedente), ma al main senza il tipo di ritorno specificato. In C++ invece mi pare di ricordare che ci fosse proprio scritto che è permesso solo int main (ora si è fatto tardi, casomai controllo domani)
 
Purtroppo da Cell non mi carica le immagini... Appena torno a casa gli do uno sguardo, cmq per quello che ho letto (la prima parte) ho già imparato tanti errori che avrei sicuramente commesso
 
@SpeedJack ottima guida,utile per me che sto imparando da poco il C++ ;). Mi mancavano le tue guide :asd:.
Vorrei chiederti delle cose:
1) Tu dici che system("pause"); deve essere inclusa nella libreria stdlib: ma io non richiamo mai questa libreria, allora, perchè mi funziona comunque system("pause"); ?
1) - 2) - 99) :asd:.
 
Ultima modifica da un moderatore:
C'e' un aspetto decisamente piu' interessante del comand system, ed' e' quello di usarlo!

E' ovvio che un system("PAUSE") serve a poco e comunque ci sono n-mila modi per fare la stessa cosa.

Quando usarlo? Un caso classico e' quando si ha un eseguibila da linea di comando che deve essere richiamato per un qualche motivo, e che fa qualcosa di decisamente piu' utile che non un 'pause'.
La parte decisamente interessante arriva ora, pero':

1) intercettare ed analizzare in real time l'output, ad esempio per tenere traccia, mediante una progress bar, dello stato di avanzamento, oppure per interpretare le eventuali segnalazioni di errore, oppure ricuperare i dati generati
2) interagire con il programma quando questo, per un qualche motivo, chiede lun qualche input da parte dell'utente

E qui' si che c'e' da divertirsi perche' l'implementazione non e' per nulla banale.

O almeno non lo e' per chi sa poco di espressioni regolari, thread e pipe ;)


Ma se vogliamo vedere la questione sicurezza, ci sono 3 problemi:

1) e' vero che chi crea il programma che usa 'system()' dovrebbe in qualche modo assicurarsi che il programma chiamato faccia proprio quello che si aspetta (e questo e' relativamente semplice, se si analizza l'output del programma chiamato)
2) ma e' anche vero che chi usa il programma creato, dovrebbe essere sicuro di usare proprio quello e non un suo alter ego malevolo ;)
3) certo, c'e' sempre la possibilita' che il genio del male di turno abbia creato un programa che genera un output plausibile ma che che faccia tutto altro!

Ma anche per questa situazione, ci sono N possibili soluzioni ;)
 
Purtroppo da Cell non mi carica le immagini... Appena torno a casa gli do uno sguardo, cmq per quello che ho letto (la prima parte) ho già imparato tanti errori che avrei sicuramente commesso

Non ascoltarlo non sa manco far fare 2 + 2 in php figuriamoci in C++
dopo questo la tua guida mi è stata molto utile avevo combinato certe cose con il main :asd:..
 
Vorrei chiederti delle cose:
1) Tu dici che system("pause"); deve essere inclusa nella libreria stdlib: ma io non richiamo mai questa libreria, allora, perchè mi funziona comunque system("pause"); ?
Semplice...
I compilatori C spesso supportano anche le dichiarazioni implicite. Cioè se il compilatore non trova la dichiarazione della funzione che vuoi utilizzare nei file header inclusi, allora prova ad indovinarla... e ci riesce: il compilatore indovina che il prototipo della funzione deve essere:
int system(const char *);
e allora aggiunge questo prototipo al codice.

Però non è cosa da fare: i file header e le dichiarazioni devono sempre essere presenti. Le dichiarazioni implicite non sono mai sicure.
 
[MENTION=210785]catyaa[/MENTION] ha spiegato egregiamente ciò che intendevo!
[MENTION=100009]SpeedJack[/MENTION] complimenti per il topic, merita il rilievo! Basta tenerlo aggiornato, introducendo anche le buone pratiche di programmazione in senso più ampio (estetica, indentazione ecc).
Bel lavoro! Grazie
 
Ultima modifica:
Topic interessantissimo, verrà fuori un bel lavoro.
Possiamo assumere per vero il fatto che nel prossimo futuro pause.exe non verrà deprecato... verosimilmente!

Non puoi mai assumere una cosa del genere, non si sa mai cosa possono togliere, specialmente nel caso di windows che proprio in questo periodo Microsoft lo sta riscrivendo per farlo funzionare su smartphone, tablet e pc contemporaneamente, oltre al fatto che hanno intenzione di deprecare le API Win32 in favore delle WinRT. Su linux poi ci sono tante di quelle distro che non mi stupirei se ne nascesse qualcuna che non supporta quei comandi XD. Inoltre di geni del male che vanno a sostituire pause.exe con uno malevolo ce ne sono :asd:. Pensa a quanti nelle scuole/università usano ancora system("PAUSE"), nella mia scuola non c'erano protezioni sui file di sistema, era uno scherzo cambiare un file del genere con uno malevolo.

Per quanto riguarda la questione della pausa io ho trovato molto utile getch(), peccato che non funzioni dappertutto. Poi c'è chi dice che cin.get() sia uguale, ma getch() fa una cosa (di suo) che cin.get() non fa: nascondere l'input digitato da tastiera. Ho approfondito la questione e ho scoperto che questa è una cosa che dipende dall'OS, e che tramite delle API dell'OS stesso è possibile nascondere l'inserimento dell'input. Infine manca una cosa che anche pause.exe ha: non c'è bisogno di premere invio per l'inserimento dei dati ("premere un tasto per continuare...", un qualsiasi tasto e soltanto quello). Ho cercato ancora e ho visto che va disattivato il buffer sull'inserimento dei dati. Quindi per rendere uguale cin.get() a getch() si dovrebbe fare qualcosa del genere:
Codice:
input_da_tastiera("nascondi", "unbuffered");
cin.get();
input_da_tastiera("mostra", "buffered");
Se ho tempo cerco di scriverla quanto più cross platform possibile, potrebbe servire, non si sa mai ;).

@catyaa questo sicuramente è un argomento interessante, anche se il modo "più sicuro" (che poi tanto sicuro non è) sarebbe quello di richiamare programmi scritti da te stesso, insomma che sai quel che fanno. Un dubbio che mi viene è sulla parte del recuperare l'output del programma, con system() non puoi (o meglio non credo), a meno che non fai una cosa del genere:
Codice:
system("programma.exe >output.txt");
ma così non sarebbe in real time. A questo punto credo sia meglio usare le API di sistema, tanto (come dice Simur) con un paio di #ifdef sistemi tutto XD (usando le API specifiche per ogni OS).
 
Il punto 3 non è necessariamente vero nel nuovo standard (anche se è meglio seguire il tuo consiglio), i punti 2 e 4 aggiungo che pure questi problemi esistono per qualsiasi linguaggio e nel punto 5 non ho capito qual'è il problema.

Il problema è che rischi una segmentation fault se non li usi con la stessa attenzione che usi per i puntatori. Essendo una classe molti potrebbero pensare che lanci qualche eccezione anche se non è così.

Riguardo l'uso del system("pause") consiglio di eseguire sempre un controllo d'integrità dell'eseguibile richiamato ma se si può evitare è meglio.
 
1) intercettare ed analizzare in real time l'output, ad esempio per tenere traccia, mediante una progress bar, dello stato di avanzamento, oppure per interpretare le eventuali segnalazioni di errore, oppure ricuperare i dati generati
2) interagire con il programma quando questo, per un qualche motivo, chiede lun qualche input da parte dell'utente
Il problema è che system ti fornisce solo quello che ritorna l'eseguibile, ovvero 0 se tutto fila liscio.
Per analizzare in real time l'output dovresti usare un'altra funzione dipendente dall'os per ricavare il pid del processo, sperare che quel pid appartenga veramente al processo che hai lanciato tu (ovvero: non è detto che ci sia un solo "pippo.exe" in esecuzione), sperare che non succedano casini all'eseguibile (es. si chiude) che hai lanciato prima che tu riesca a prenderne il controllo, ecc...
Senza contare che tutto questo dovresti farlo su un thread separato, perché non è detto che la system non sia bloccante (e solitamente è bloccante).

E con queste considerazione cadono anche i 3 punti sulla sicurezza che hai citato dopo.

Niente ti vieta di richiamare la shell con un comando usando fork, exec, CreateProcess o ShellExecute. Sarebbe quasi come usare system, ma ottieni molte più informazioni e risolvi alcuni dei problemi che ho indicato sopra e nel post precedente, inoltre sai esattamente quello che succede.
Se si vuole scrivere codice portable sono sicuro che esistano delle librerie che aiutano parecchio, ma la system secondo me è troppo implementation-defined per essere usata per qualcosa di minimamente serio. Teoricamente bisognerebbe andarci cauti anche con gli script visto che non sai che shell si apre (fortunatamente POSIX lascia un po' meno incognite -- link).
 
Non so se chiederlo qui o aprire una nuova discussione, ma io ho letto su internet che con cin.get() del tipo che si può usarlo una volta sola , un sito faceva un esempio dell'utilizzo e diceva qualcosa sulla "nuova" riga e consigliava di usare cin.getline() , qualcuno può dirmi di + ?
 
Guida molto interessante, soprattutto molto utile per i newbie come me che non hanno voglia di documentsi su tutto ciò che si studia.
Veramente ottimo lavoro! Continua ad aggiornarla che mi sarà molto utile! :D