Le variabili globali sono cattive?

In C / C ++, le variabili globali sono così gravi come il mio professore pensa che siano?

Il problema con le variabili globali è che poiché ogni funzione ha accesso a queste, diventa sempre più difficile capire quali funzioni effettivamente leggono e scrivono queste variabili.

Per capire come funziona l’applicazione, è necessario prendere in considerazione tutte le funzioni che modificano lo stato globale. Ciò può essere fatto, ma man mano che l’applicazione cresce diventerà più difficile fino al punto di essere praticamente imansible (o almeno una completa perdita di tempo).

Se non si fa affidamento su variabili globali, è ansible passare lo stato tra diverse funzioni secondo necessità. In questo modo hai una possibilità molto migliore di capire cosa fa ciascuna funzione, poiché non è necessario tenere conto dello stato globale.

L’importante è ricordare l’objective generale: chiarezza

La regola “nessuna variabile globale” esiste perché la maggior parte delle volte le variabili globali rendono meno chiaro il significato del codice.

Tuttavia, come molte regole, le persone ricordano la regola e non ciò che la regola era destinata a fare.

Ho visto programmi che sembrano raddoppiare le dimensioni del codice passando un numero enorme di parametri semplicemente per evitare il male delle variabili globali. Alla fine, l’utilizzo di globals avrebbe reso il programma più chiaro a chi lo leggeva. Seguendo scrupolosamente la parola della regola, il programmatore originale aveva fallito l’intento della regola.

Quindi, sì, i globals sono spesso cattivi. Ma se senti che alla fine, l’intento del programmatore è reso più chiaro dall’uso di variabili globali, quindi vai avanti. Tuttavia, ricorda il calo di chiarezza che si verifica automaticamente quando costringi qualcuno ad accedere a un secondo pezzo di codice (i globali) per capire come funziona il primo pezzo.

Il mio professore diceva qualcosa del tipo: usare le variabili globali va bene se le usi correttamente. Non credo di essermi mai abituato a usarli correttamente, quindi li ho usati raramente.

Le variabili globali dovrebbero essere utilizzate solo quando non ci sono alternative. E sì, questo include Singletons. Il 90% delle volte vengono introdotte variabili globali per risparmiare il costo del passaggio di un parametro. E poi accade il multithreading / test di unità / codice di manutenzione, e tu hai un problema.

Quindi sì, nel 90% delle situazioni le variabili globali sono cattive. Le eccezioni non saranno probabilmente viste da te negli anni del tuo college. Un’eccezione che mi viene in mente è che si tratta di oggetti intrinsecamente globali come le tabelle degli interrupt. Cose come la connessione DB sembrano essere globali, ma non lo sono.

Sì, ma non devi sostenere il costo delle variabili globali finché non smetti di lavorare nel codice che utilizza le variabili globali e inizia a scrivere qualcos’altro che utilizza il codice che utilizza le variabili globali. Ma il costo è ancora lì.

In altre parole, è un costo indiretto a lungo termine e in quanto tale la maggior parte delle persone pensa che non sia male.

Risponderei a questa domanda con un’altra domanda: usi singeltons / I single sono cattivi?

Perché (quasi tutti) l’uso di singelton è una variabile globale glorificata.

Se è ansible che il tuo codice finisca sotto una revisione approfondita durante un processo in Corte Suprema , allora vuoi essere sicuro di evitare le variabili globali.

Vedi questo articolo: Il codice etilometro Buggy riflette l’importanza della revisione della fonte

Ci sono stati alcuni problemi con lo stile del codice che sono stati identificati da entrambi gli studi. Uno dei problemi stilistici che riguardavano i revisori era l’uso estensivo di variabili globali non protette . Questo è considerato di scarsa qualità perché aumenta il rischio che lo stato del programma diventi incoerente o che i valori vengano inavvertitamente modificati o sovrascritti. I ricercatori hanno anche express alcune preoccupazioni sul fatto che la precisione decimale non è mantenuta in modo coerente in tutto il codice.

Amico, scommetto che gli sviluppatori desiderano che non abbiano usato le variabili globali!

Il problema che le variabili globali creano per il programmatore è che espande la superficie di accoppiamento inter-componente tra i vari componenti che stanno usando le variabili globali. Ciò significa che con l’aumentare del numero di componenti che utilizzano una variabile globale, la complessità delle interazioni può anche aumentare. Questo aumento dell’accoppiamento di solito rende i difetti più facili da iniettare nel sistema quando si apportano modifiche e rende anche i difetti più difficili da diagnosticare e correggere. Questo aumento dell’accoppiamento può anche ridurre il numero di opzioni disponibili quando si apportano modifiche e può aumentare lo sforzo richiesto per le modifiche, poiché spesso è necessario tracciare i vari moduli che utilizzano anche la variabile globale per determinare le conseguenze delle modifiche.

Lo scopo dell’incapsulamento , che è fondamentalmente l’opposto dell’utilizzo di variabili globali, è quello di ridurre l’accoppiamento al fine di rendere la comprensione e la modifica della fonte più facile, più sicura e più facilmente testata. È molto più semplice utilizzare il test delle unità quando non vengono utilizzate variabili globali.

Ad esempio se si dispone di una variabile intera globale semplice che viene utilizzata come indicatore numerato che vari componenti utilizzano come macchina di stato e quindi si apporta una modifica aggiungendo un nuovo stato per un nuovo componente, è necessario quindi tracciare tutti gli altri componenti per garantire che il cambiamento non li riguardi. Un esempio di un ansible problema potrebbe essere se un’istruzione switch per verificare il valore della variabile globale di enumerazione con le istruzioni case per ciascuno dei valori correnti sia utilizzata in vari punti e si verifichi che alcune delle istruzioni switch non abbiano una caso default per gestire un valore imprevisto per il globale, tutto ad un tratto si ha un comportamento indefinito per quanto riguarda l’applicazione.

D’altra parte l’uso di un’area dati condivisa può essere usato per contenere un insieme di parametri globali a cui si fa riferimento in tutta l’applicazione. Questo approccio viene spesso utilizzato con applicazioni incorporate con impronte di memoria di piccole dimensioni.

Quando si utilizzano variabili globali in questo tipo di applicazioni, in genere la responsabilità per la scrittura nell’area dati viene assegnata a un singolo componente e tutti gli altri componenti vedono l’area come const e ne legge da zero, non scrivendovi mai. L’adozione di questo approccio limita i problemi che possono svilupparsi.

Qui ci sono alcuni problemi con l’utilizzo di variabili globali che devono essere aggirate.

Quando l’origine di una variabile globale come una struct viene modificata, tutto ciò che la usa deve essere ricompilata in modo che tutto ciò che utilizza la variabile conosca le sue vere dimensioni e il modello di memoria.

Se più di un componente può modificare la variabile globale, è ansible incorrere in problemi con dati incoerenti nella variabile globale. Con un’applicazione multi-threading, probabilmente dovrai aggiungere qualche tipo di blocco o area critica per fornire un modo in modo che solo un thread alla volta possa modificare la variabile globale e quando un thread sta modificando la variabile, tutte le modifiche sono complete e impegnato prima che altri thread possano interrogare la variabile o modificarla.

Il debug di un’applicazione multi-thread che utilizza una variabile globale può essere più difficile. È ansible imbattersi in condizioni di gara che possono creare difetti difficili da replicare. Con diversi componenti che comunicano attraverso una variabile globale, specialmente in un’applicazione multi-thread, essere in grado di sapere quale componente sta cambiando la variabile quando e come sta cambiando la variabile può essere molto difficile da capire.

Il conflitto di nomi può essere un problema con l’utilizzo di variabili globali. Una variabile locale che ha lo stesso nome di una variabile globale può hide la variabile globale. Esegui anche il problema della convenzione di denominazione quando usi il linguaggio di programmazione C. Una soluzione è dividere il sistema in sottosistemi con le variabili globali per un particolare sottosistema che iniziano tutte con le stesse prime tre lettere (vedi questo sulla risoluzione delle collisioni nello spazio dei nomi nell’objective C ). C ++ fornisce spazi dei nomi e con C puoi aggirare questo creando una struttura visibile a livello globale i cui membri sono vari elementi di dati e puntatori a dati e funzioni che sono forniti in un file come statici quindi con visibilità del file solo in modo che possano essere referenziati solo attraverso la struttura globalmente visibile.

In alcuni casi, l’intento originale dell’applicazione viene modificato in modo che le variabili globali che hanno fornito lo stato per un singolo thread vengano modificate per consentire l’esecuzione di più thread duplicati. Un esempio potrebbe essere una semplice applicazione progettata per un singolo utente che utilizza variabili globali per lo stato e quindi una richiesta scende dalla gestione per aggiungere un’interfaccia REST per consentire alle applicazioni remote di agire come utenti virtuali. Quindi ora ti capita di dover duplicare le variabili globali e le loro informazioni di stato in modo che il singolo utente e ciascuno degli utenti virtuali da applicazioni remote abbiano il proprio set unico di variabili globali.

Le variabili globali sono pessime come le rendi, non meno.

Se si sta creando un programma completamente incapsulato, è ansible utilizzare le globali. È un “peccato” usare i globali, ma i peccati di programmazione sono filosoficamente fiabeschi.

Se controlli L.in.oleum , vedrai una lingua le cui variabili sono esclusivamente globali. Non è scalabile perché le biblioteche non hanno altra scelta che usare i globals.

Detto questo, se si hanno delle scelte e si può ignorare la filosofia del programmatore, i globals non sono poi così male.

Neanche Gotos, se li usi bene.

Il grosso problema “cattivo” è che, se le usi male, la gente urla, il lander marcio si schianta e il mondo esplode … o qualcosa del genere.

Come qualcuno ha detto (sto parafrasando) in un altro thread “Regole come questa non dovrebbero essere infranti, fino a quando non comprenderete appieno le conseguenze di ciò.”

Ci sono momentjs in cui le variabili globali sono necessarie, o almeno molto utili (ad esempio, si sta lavorando con richiami definiti dal sistema). D’altra parte, sono anche molto pericolosi per tutte le ragioni che ti sono state dette.

Ci sono molti aspetti della programmazione che dovrebbero probabilmente essere lasciati agli esperti. A volte hai bisogno di un coltello molto affilato. Ma non puoi usarne uno finché non sei pronto …

Le variabili globali sono generalmente cattive, specialmente se altre persone stanno lavorando sullo stesso codice e non vogliono spendere 20 minuti per cercare tutti i posti a cui fa riferimento la variabile. E l’aggiunta di thread che modificano le variabili porta a un nuovo livello di mal di testa.

Le costanti globali in uno spazio dei nomi anonimo, utilizzate in una singola unità di traduzione, sono belle e onnipresenti nelle app e nelle librerie professionali. Ma se i dati sono mutabili e / o devono essere condivisi tra più TU, potresti voler incapsularlo, se non per motivi di progettazione, quindi per il debug o il lavoro con il tuo codice.

Usare le variabili globali è un po ‘come spazzare sporcizia sotto un tappeto. È una soluzione rapida e molto più facile a breve termine che ottenere un dust-pad o un aspirapolvere per ripulirlo. Tuttavia, se finirai per spostare il tappeto più tardi, avrai un grande casino a sorpresa sotto.

Il problema è meno che sono cattivi , e più che sono pericolosi . Hanno il loro set di pro e contro, e ci sono situazioni in cui sono o il modo più efficiente o unico per raggiungere un compito particolare. Tuttavia, sono molto facili da abusare, anche se si adottano le misure per utilizzarli sempre correttamente.

Alcuni professionisti:

  • È ansible accedere da qualsiasi funzione.
  • Si può accedere da più thread.
  • Non andrà mai fuori portata fino alla fine del programma.

Alcuni contro:

  • È ansible accedere da qualsiasi funzione, senza dover essere esplicitamente trascinato come parametro e / o documentato.
  • Non thread-safe.
  • Inquina lo spazio dei nomi globale e potenzialmente causa conflitti di nomi, a meno che non vengano prese misure per impedirlo.

Nota, se vuoi, che i primi due pro e i primi due contro elencati sono esattamente la stessa cosa, solo con parole diverse. Questo perché le caratteristiche di una variabile globale possono effettivamente essere utili, ma le stesse caratteristiche che le rendono utili sono la fonte di tutti i loro problemi.

Alcune potenziali soluzioni ad alcuni dei problemi:

  • Considerare se sono effettivamente la soluzione migliore o più efficiente per il problema. Se ci sono soluzioni migliori, usa quello.
  • Inserirli in un namespace [C ++] o singleton struct [C, C ++] con un nome univoco (un buon esempio sarebbe Globals o GlobalVars ), o usare una convenzione di denominazione standardizzata per variabili globali (come global_[name] o g_module_varNameStyle ( come menzionato da underscore_d nei commenti)). Questo documenterà entrambi il loro utilizzo (puoi trovare il codice che usa le variabili globali cercando il namespace / nome della struttura) e minimizzare l’impatto sullo spazio dei nomi globale.
  • Per qualsiasi funzione che accede a variabili globali, documenta esplicitamente quali variabili legge e quali scrive. Ciò faciliterà la risoluzione dei problemi.
  • Inseriscili nel proprio file sorgente e dichiarali extern nell’intestazione associata, in modo che il loro utilizzo possa essere limitato alle unità di compilazione che devono accedervi. Se il tuo codice si basa su molte variabili globali, ma ciascuna unità di compilazione ha solo bisogno di accedere ad una manciata di esse, potresti prendere in considerazione l’ordinamento in più file sorgente, quindi è più facile limitare l’accesso di ciascun file alle variabili globali.
  • Impostare un meccanismo per bloccarli e sbloccarli, e / o progettare il codice in modo che il numero minimo di funzioni possibili necessiti effettivamente di modificare le variabili globali. Leggendoli è molto più sicuro che scriverli, anche se le gare di thread possono ancora causare problemi nei programmi con multithreading.
  • Fondamentalmente, minimizza l’accesso a loro e massimizza l’unicità del nome. Vuoi evitare le collisioni di nomi e avere il minor numero ansible di funzioni in grado di modificare potenzialmente una determinata variabile.

Se sono buoni o cattivi dipende da come li usi. La maggioranza tende ad usarli male, da qui la generale diffidenza nei loro confronti. Se usati correttamente, possono essere un vantaggio importante; se usati male, tuttavia, possono e torneranno a morderti quando e quanto meno te lo aspetti.

Un buon modo per vederlo è che loro stessi non sono cattivi, ma abilitano un cattivo design e possono moltiplicare in modo esponenziale gli effetti del cattivo design.


Anche se non intendi usarli, è meglio sapere come usarli in sicurezza e scegliere di non farlo, piuttosto che non usarli perché non sai come usarli in modo sicuro. Se ti trovi in ​​una situazione in cui è necessario mantenere il codice preesistente che si basa su variabili globali, potresti non essere in grado di affrontare difficoltà se non sai come usarle correttamente.

Le variabili globali sono cattive se consentono di manipolare aspetti di un programma che dovrebbero essere modificati solo localmente. In OOP i globali spesso sono in conflitto con l’idea di incapsulamento.

Penso che il tuo professore stia cercando di fermare una ctriggers abitudine prima ancora che inizi.

Le variabili globali hanno il loro posto e come molte persone hanno detto di sapere dove e quando usarle possono essere complicate. Quindi penso piuttosto che entrare nel nocciolo del perché, come, quando e dove delle variabili globali il tuo professore ha deciso di vietare. Chi lo sa, potrebbe vietarli in futuro.

Assolutamente no. Ma abusare di loro … è male.

Rimuoverli senza cervello per il gusto è solo … senza mente. A meno che tu non conosca i vantaggi e gli svantaggi, è meglio evitare e fare come ti è stato insegnato / imparato, ma non c’è nulla di implicitamente sbagliato nelle variabili globali. Quando capisci che i pro e i contro faranno meglio la tua decisione.

Le variabili globali vanno bene nei programmi piccoli, ma orribili se usate allo stesso modo in quelle grandi.

Ciò significa che puoi facilmente prendere l’abitudine di usarli durante l’apprendimento. Questo è ciò che il tuo professore sta cercando di proteggerti.

Quando sei più esperto sarà più facile imparare quando stanno bene.

Sì, perché se lasci che i programmatori incompetenti li usino (leggi il 90% in particolare gli scienziati) finisci con oltre 600 variabili globali distribuite su oltre 20 file e un progetto di 12.000 linee in cui l’80% delle funzioni diventa nullo, restituisce vuoto e opera interamente sullo stato globale.

Diventa rapidamente imansible capire cosa sta succedendo in qualsiasi punto, a meno che tu non conosca l’intero progetto.

No, non sono affatto male. È necessario guardare il codice (macchina) prodotto dal compilatore per fare questa determinazione, a volte è molto peggio usare un locale piuttosto che un globale. Si noti inoltre che mettere “statico” su una variabile locale lo rende fondamentalmente globale (e crea altri problemi brutti che un vero globale risolverebbe). “globals locali” sono particolarmente cattivi.

Globali ti danno un controllo pulito sull’utilizzo della memoria, qualcosa di molto più difficile da fare con i locali. In questi giorni è importante solo in ambienti embedded in cui la memoria è piuttosto limitata. Qualcosa da sapere prima di supporre che l’embedded sia lo stesso degli altri ambienti e presupponga che le regole di programmazione siano le stesse su tutta la linea.

È bene che tu metta in discussione le regole insegnate, la maggior parte di esse non è per le ragioni che ti vengono dette. La lezione più importante però non è che questa è una regola da portare con te per sempre, ma questa è una regola richiesta per onorare al fine di superare questa class e andare avanti. Nella vita troverai che per la compagnia XYZ avrai altre regole di programmazione che dovrai alla fine onorare per poter ottenere uno stipendio. In entrambe le situazioni puoi argomentare la regola, ma penso che avrai una fortuna molto migliore in un lavoro che a scuola. Sei solo un altro di molti studenti, il tuo posto sarà presto sostituito, i professori non lo faranno, in un lavoro sei una piccola squadra di giocatori che devono vedere questo prodotto fino alla fine e in quell’ambiente le regole sviluppate sono per il beneficio dei membri del team, del prodotto e dell’azienda, quindi se tutti sono interessati o se per il particolare prodotto ci sono buone ragioni ingegneristiche per violare qualcosa che hai imparato al college o qualche libro sulla programmazione generica, allora vendi la tua idea a la squadra e scriverla come un metodo valido se non il preferito. Tutto è un gioco leale nel mondo reale.

Se segui tutte le regole di programmazione insegnate a scuola o nei libri, la tua carriera di programmatore sarà estremamente limitata. È probabile che tu possa sopravvivere e avere una carriera fruttuosa, ma l’ampiezza e la larghezza degli ambienti a tua disposizione saranno estremamente limitate. Se sai come e perché la regola è lì e puoi difenderla, è una buona cosa, se ragiona solo perché “il mio insegnante ha detto così”, beh, non è così bello.

Tieni presente che argomenti come questo sono spesso discussi sul posto di lavoro e continueranno ad esserlo, man mano che i compilatori e i processori (e le lingue) si evolvono, così fanno questo tipo di regole e senza difendere la tua posizione e forse una lezione da qualcuno con un’altra opinione andare avanti

Nel frattempo, poi fai quello che dice il più forte o recita il bastone più grande (fino a quando tu non sei quello che urla più forte e porta il bastone più grande).

L’uso di variabili globali dipende in realtà dai requisiti. Il suo vantaggio è che, riduce il sovraccarico di passare ripetutamente i valori.

Ma il tuo professore ha ragione perché solleva problemi di sicurezza, quindi l’uso di variabili globali dovrebbe essere evitato il più ansible. Le variabili globali creano anche problemi a volte difficili da eseguire il debug .

Per esempio:-

Situazioni in cui i valori delle variabili vengono modificati in fase di esecuzione . In quel momento è difficile identificare quale parte del codice lo sta modificando e a quali condizioni.

Mi piacerebbe discutere contro il punto che viene fatto in tutto questo thread che rende multi-threading più difficile o imansible di per sé. Le variabili globali sono stati condivisi, ma le alternative ai globali (ad esempio i puntatori che passano in giro) potrebbero anche condividere lo stato. Il problema con il multithreading è come utilizzare correttamente lo stato condiviso, non se lo stato è condiviso tramite una variabile globale o qualcos’altro.

La maggior parte delle volte quando fai multi-threading devi condividere qualcosa. Ad esempio, in uno schema produttore-consumatore, è ansible condividere una coda thread-safe che contiene le unità di lavoro. E tu sei autorizzato a condividerlo perché quella struttura dati è thread-safe. Se quella coda è globale o meno è del tutto irrilevante quando si parla di sicurezza del thread.

La speranza implicita espressa in tutto questo thread che trasforma un programma da single-threaded a multi-threaded sarà più facile quando non utilizzare i globals è ingenuo. Sì, i globali ti consentono di spararti più facilmente ai piedi, ma ci sono molti modi per spararti.

Non sto sostenendo i globali, poiché gli altri punti continuano a sussistere, il mio punto è semplicemente che il numero di thread in un programma non ha nulla a che fare con l’ambito delle variabili.

Prima o poi dovrai cambiare il modo in cui è impostata la variabile o cosa succede quando ti si accede, oppure devi solo cercare dove è cambiato.

È sempre meglio non avere variabili globali. Basta scrivere alla diga e impostare i metodi, e sii ghiandola quando ne hai bisogno un giorno, una settimana o un mese dopo.

Di solito uso globals per valori che raramente vengono modificati come singletons o puntatori di funzioni alle funzioni nella libreria caricata dynamicmente. L’uso di globalmente mutabili nelle applicazioni multithread tende a portare a un bug difficile da tracciare, quindi cerco di evitarlo come regola generale.

Usare un global anziché passare un argomento è spesso più veloce ma se stai scrivendo un’applicazione multithread, cosa che fai spesso al giorno d’oggi, generalmente non funziona molto bene (puoi usare thread-statics ma il guadagno in termini di prestazioni è discutibile) .

Alla fine della giornata, il tuo programma o la tua app possono ancora funzionare, ma è questione di essere in ordine e di avere una completa comprensione di cosa sta succedendo. Se si condivide un valore variabile tra tutte le funzioni, può diventare difficile rintracciare quale funzione sta cambiando il valore (se la funzione lo fa) e rende il debug un milione di volte più difficile

Globali sono buoni quando si tratta di configurazione . Quando vogliamo che la nostra configurazione / modifiche abbiano un impatto globale sull’intero progetto .

Quindi possiamo cambiare una configurazione e le modifiche sono dirette all’intero progetto . Ma devo avvertirti che dovresti essere molto intelligente per usare i globals.

la sicurezza è meno significa che chiunque può manipolare le variabili se sono dichiarate globali, per spiegare questo esempio, se si dispone di un saldo come variabile globale nel proprio programma bancario, la funzione utente può manipolarlo così come il funzionario bancario può anche manipolare questo quindi c’è un problema. Solo l’utente dovrebbe avere la funzione di sola lettura e ritiro, ma l’impiegato della banca può aggiungere l’importo quando l’utente dà personalmente i soldi nella scrivania.questo è il modo in cui funziona

Nelle applicazioni web all’interno di un’azienda può essere utilizzato per tenere dati sessione / finestra / thread / utente specifici sul server per ragioni di ottimizzazione e per preservare dalla perdita di lavoro in caso di connessione instabile. Come già detto, le condizioni di gara devono essere gestite. Usiamo una singola istanza di una class per questa informazione ed è gestita con attenzione.

In un’applicazione multi-thread, utilizzare le variabili locali al posto delle variabili globali per evitare una condizione di competizione.

Una condizione di competizione si verifica quando più thread accedono a una risorsa condivisa, con almeno un thread con accesso in scrittura ai dati. Quindi, il risultato del programma non è prevedibile e dipende dall’ordine di accesso ai dati da diversi thread.

Maggiori informazioni su questo qui, https://software.intel.com/en-us/articles/use-intel-parallel-inspector-to-find-race-conditions-in-openmp-based-multithreaded-code