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.
 
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à.
 
Una cosa da non fare mai e poi mai che secondo me andrebbe aggiunta alla lista è quella di scrivere programmi che fanno affidamento su undefined behavior perchè finchè si compila tutto senza ottimizzazioni si va piuttosto tranquilli, ma quando si compila con -O2 o -O3 si rischia che il compilatore cancelli porzioni di codice introducendo falle di sicurezza.

Ad esempio supponiamo di avere una variabile int chiamata "x" e di volere aggiungere a questa variabile un valore numerico, diciamo 1000, tuttavia vogliamo anche controllare che non avvenga nessun overflow, con un codice tipo "if (x+1000<x)".
Questo funzionerebbe (e funziona, senza ottimizzazioni) sulla stragrande maggioranza delle architetture dove gli overflow causano semplicemente un wrap around e quindi ci si ritrova con un risultato negativo e minore di x, ma per coprire tutti i casi lo standard C definisce l'integer overflow come undefined behavior.
A questo punto il compilatore è autorizzato ad assumere che una condizione come "if (x+1000<x)" sarà sempre falsa perchè nell'unico caso in cui è vera è autorizzato dallo standard a fare quello che vuole ed eliminare completamente l'if (e il blocco di codice da eseguire nel caso sia vero).

Un'esempio real life è tratto dal kernel di linux:
Codice:
struct tun_struct *tun = ...;
struct sock *sk = tun->sk;
if
   (!tun)
return POLLERR;
/* write to address based on tun */

Visto che il puntatore tun è dereferenziato prima del !tun che controlla che non sia null il compilatore assume che il puntatore non sia null, perchè il dereferenziamento di un puntatore null è undefined behavior ed elimina completamente l'if, creando potenziali falle di sicurezza.




Qua lo ho spiegato molto alla svelta, traendo informazioni da questo articolo che consiglio di leggere per una spiegazione pi# precisa e completa http://pdos.csail.mit.edu/~xi/papers/stack-sosp13.pdf
 
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.
 
3) Evitare di chiedere cosa evitare, è da principianti X'D
Ammettere di essere principianti magari, o comunque aver desiderio di imparare di più su un certo argomento, ti rende sicuramente una persona più responsabile. Avere (spesso) l'arroganza di conoscere tutto su un certo argomento porta a errori in egual misura.

Se non si sa qualcosa meglio chiedere che rimanere nel dubbio ed eventualmente fare errori che si protrarrebbero per chissà quanto, no? :)
 
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
È Tapatalk il problema (anche a me non le visualizza), e in genere taglia via anche le parti di codice che hanno al loro interno i simboli < e >. Apri inforge dal browser dello smartphone e non avrai problemi
 
  • Mi piace
Reazioni: Ryou
Non la trovo :/
vai nella home di tapatalk (quindi fuori dal forum), clicca in alto a destra sui tre puntini-->impostazioni. Scorri fino a: preferenze di caricamento delle immagini e assicurati che sia tutto spuntato, controlla anche preferenze di caricamento con connessione lenta, non si sa mai ;)
 
  • Mi piace
Reazioni: Ryou
Ammettere di essere principianti magari, o comunque aver desiderio di imparare di più su un certo argomento, ti rende sicuramente una persona più responsabile. Avere (spesso) l'arroganza di conoscere tutto su un certo argomento porta a errori in egual misura.

Se non si sa qualcosa meglio chiedere che rimanere nel dubbio ed eventualmente fare errori che si protrarrebbero per chissà quanto, no? :)

Hai interpretato male il messaggio, la mia era semplice ironia. Comunque, il tuo discorso non fa una piega.
 
  • Mi piace
Reazioni: Scanetatore
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...
 
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