Wanneer is het oké om een ​​globale variabele in C te gebruiken?

Blijkbaar is er veel variatie in meningen, variërend van “Nooit! Altijd inkapselen (zelfs als het met een macro is!)” tot “Het maakt niet uit – gebruik ze wanneer het handiger is dan niet.

Dus.

Specifieke, concrete redenen (bij voorkeur met een voorbeeld)

  • Waarom globale variabelen gevaarlijk zijn
  • Wanneer globale variabelen moetenworden gebruikt in plaats van alternatieven
  • Welke alternatieven zijn er voor degenen die in de verleiding komen om globale variabelen ongepast te gebruiken

Hoewel dit subjectief is, zal ik één antwoord kiezen (dat voor mij het beste de haat-liefdeverhouding weergeeft die elke ontwikkelaar zou moeten hebben met globals) en de community zal het hunne net daaronder stemmen.

Ik denk dat het voor nieuwelingen belangrijk is om dit soort referenties te hebben, maar maak het alsjeblieft niet te vol als er een ander antwoord bestaat dat in grote lijnen lijkt op het jouwe – voeg een opmerking toe of bewerk het antwoord van iemand anders.

-Adam


Antwoord 1, autoriteit 100%

Variabelen moeten altijd een kleiner bereik hebben. Het argument daarachter is dat elke keer dat je het bereik vergroot, je meer code hebt die de variabele mogelijk wijzigt, waardoor de oplossing meer complexiteit krijgt.

Het is dus duidelijk dat het vermijden van het gebruik van globale variabelen de voorkeur heeft als het ontwerp en de implementatie dat natuurlijk toestaan. Daarom gebruik ik liever geen globale variabelen, tenzij ze echt nodig zijn.

Ik kan het ook niet eens zijn met de ‘nooit’-stelling. Net als elk ander concept zijn globale variabelen iets dat alleen moet worden gebruikt wanneer dat nodig is. Ik zou liever globale variabelen gebruiken dan wat kunstmatige constructies (zoals het doorgeven van aanwijzers), die alleen de echte bedoeling zouden maskeren.

Enkele goede voorbeelden waarbij globale variabelen worden gebruikt, zijn implementaties van singleton-patronen of registertoegang in embedded systemen.

Over het daadwerkelijk detecteren van buitensporig gebruik van globale variabelen: inspectie, inspectie, inspectie. Telkens wanneer ik een globale variabele zie, moet ik mezelf afvragen: is dat ECHT nodig bij een globale scope?


Antwoord 2, autoriteit 35%

De enige manier waarop u globale variabelen kunt laten werken, is door ze namen te geven die ervoor zorgen dat ze uniek zijn.

Die naam heeft meestal een voorvoegsel dat is gekoppeld aan een of andere “module” of verzameling functies waarvoor de globale variabele bijzonder gericht of zinvol is.

Dit betekent dat de variabele “behoort” tot die functies — het maakt er deel van uit. Inderdaad, de globale kan meestal worden “verpakt” met een kleine functie die samengaat met de andere functies — in hetzelfde .hbestand met dezelfde naam prefix.

Bonus.

Als je dat doet, is het opeens niet meer echtglobaal. Het maakt nu deel uit van een module met gerelateerde functies.

Dit kan altijdworden gedaan. Met een beetje nadenken kan elke voorheen globale variabele worden toegewezen aan een verzameling functies, toegewezen aan een specifiek .h-bestand en geïsoleerd met functies waarmee u de variabele kunt wijzigen zonder iets te breken.

In plaats van te zeggen “gebruik nooit globale variabelen”, kun je ook zeggen “wijs de verantwoordelijkheden van de globale variabele toe aan een module waar dit het meest logisch is.”


Antwoord 3, autoriteit 19%

Beschouw deze koan: “als de reikwijdte smal genoeg is, is alles globaal”.

Het is in deze tijd nog steeds heel goed mogelijk om een ​​zeer snel hulpprogramma te schrijven om een ​​eenmalige klus te klaren.

In dergelijke gevallen is de energie die nodig is om veilige toegang tot variabelen te creëren groter dan de energie die wordt bespaard door problemen op te sporen in zo’n klein hulpprogramma.

Dit is het enige geval dat ik terloops kan bedenken waar globale variabelen verstandig zijn, en het is relatief zeldzaam. Nuttige, nieuwe programma’s die zo klein zijn dat ze volledig in het kortetermijngeheugen van de hersenen kunnen worden bewaard, worden steeds zeldzamer, maar ze bestaan ​​nog steeds.

In feite zou ik stoutmoedig kunnen beweren dat als het programma niet zo klein is, globale variabelen illegaal zouden moeten zijn.

  • Als de variabele nooit zal veranderen, dan is het een constante, geen variabele.
  • Als de variabele universele toegang vereist, dan zouden er twee subroutines moeten zijn om deze op te halen en in te stellen, en ze zouden gesynchroniseerd moeten worden.
  • Als het programma klein begint en later misschien groter wordt, codeer dan alsof het programma vandaag groot is en schaft globale variabelen af. Niet alle programma’s zullen groeien! (Hoewel dat natuurlijk veronderstelt dat de programmeur soms bereid is om code weg te gooien.)

Antwoord 4, autoriteit 18%

Globale variabelen in C zijn handig om code leesbaarder te maken als een variabele vereist is door meerdere methoden (in plaats van de variabele door te geven aan elke methode). Ze zijn echter gevaarlijk omdat alle locaties de mogelijkheid hebben om die variabele aan te passen, waardoor het mogelijk moeilijk wordt om bugs op te sporen. Als u een globale variabele moet gebruiken, zorg er dan altijd voor dat deze alleen rechtstreeks door één methode wordt gewijzigd en laat alle andere bellers die methode gebruiken. Dit maakt het veel gemakkelijker om problemen met betrekking tot wijzigingen in die variabele op te sporen.


Antwoord 5, autoriteit 16%

Als je je geen zorgen maakt over thread-safe code: gebruik ze waar het zinvol is, met andere woorden waar het zinvol is om iets als een globale staat uit te drukken.

Als uw code mogelijk meerdere threads bevat: vermijd koste wat het kost. Abstracte globale variabelen in werkwachtrijen of een andere thread-veilige structuur, of indien absoluut noodzakelijk in sloten verpakken, rekening houdend met het feit dat dit waarschijnlijk knelpunten in het programma zijn.


Antwoord 6, autoriteit 7%

Ik kwam uit het “nooit”-kamp, ​​totdat ik in de defensie-industrie ging werken. Er zijn enkele industriestandaarden die vereisen dat software globale variabelen gebruikt in plaats van dynamisch (malloc in het C-geval) geheugen. Ik moet mijn benadering van dynamische geheugentoewijzing heroverwegen voor sommige van de projecten waaraan ik werk. Als u het “algemene” geheugen kunt beschermen met de juiste semaforen, threads, enz., dan kan dit een acceptabele benadering van uw geheugenbeheer zijn.


Antwoord 7, autoriteit 7%

Codecomplexiteit is niet de enige zorg voor optimalisatie. Voor veel toepassingen heeft prestatie-optimalisatie een veel grotere prioriteit. Maar wat nog belangrijker is, het gebruik van globale variabelen kan de complexiteit van de code in veel situaties drastisch VERMINDEREN. Er zijn veel, misschien gespecialiseerde, situaties waarin globale variabelen niet alleen een acceptabele oplossing zijn, maar ook de voorkeur hebben. Mijn favoriete gespecialiseerde voorbeeld is hun gebruik om communicatie te bieden tussen de hoofdthread van een applicatie met een audio-callback-functie die in een realtime thread wordt uitgevoerd.

Het is misleidend om te suggereren dat globale variabelen een verplichting zijn in toepassingen met meerdere threads, aangezien ELKE variabele, ongeacht de reikwijdte, een potentiële verplichting is als deze wordt blootgesteld aan veranderingen op meer dan één thread.

Gebruik spaarzaam globale variabelen. Waar mogelijk moeten gegevensstructuren worden gebruikt om het gebruik van de globale naamruimte te organiseren en te isoleren.

Variabele reikwijdte biedt programmeurs een zeer nuttige bescherming, maar het kan kosten met zich meebrengen. Ik kwam vanavond om over globale variabelen te schrijven omdat ik een ervaren Objective-C-programmeur ben die vaak gefrustreerd raakt door de belemmeringen die objectoriëntatie oplegt bij gegevenstoegang. Ik zou willen beweren dat anti-global fanatisme meestal afkomstig is van jongere, door theorie doordrenkte programmeurs die voornamelijk ervaring hebben met objectgeoriënteerde API’s op zichzelf, zonder een diepe, praktische ervaring met API’s op systeemniveau en hun interactie in applicatie-ontwikkeling. Maar ik moet toegeven dat ik gefrustreerd raak als leveranciers de naamruimte slordig gebruiken. Verschillende linux-distributies hadden bijvoorbeeld “PI” en “TWOPI” globaal voorgedefinieerd, waardoor veel van mijn persoonlijke code brak.


Antwoord 8, autoriteit 5%

  • Wanneer niet gebruiken:Globale variabelen zijn gevaarlijk omdat de enige manier om ooit te weten te komen hoe de globale variabele is gewijzigd, is door de volledige broncode te traceren in het .c-bestand waarin ze zijn gedeclareerd (of , alle .c-bestanden als het ook extern is). Als uw code bugs bevat, moet u uw volledige bronbestand(en) doorzoeken om te zien welke functies deze wijzigen en wanneer. Het is een nachtmerrie om te debuggen als het fout gaat. We nemen de vindingrijkheid achter het concept van lokale variabelen vaak als vanzelfsprekend aan – het is gemakkelijk te traceren
  • Wanneer te gebruiken:Algemene variabelen moeten worden gebruikt wanneer het gebruik ervan niet overdreven wordt gemaskeerd en wanneer de kosten van het gebruik van lokale variabelen buitengewoon complex zijn tot het punt waarop de leesbaarheid in gevaar komt. Hiermee bedoel ik de noodzaak om onder andere een extra parameter toe te voegen aan functieargumenten en returns en het doorgeven van pointers. Drie klassieke voorbeelden: wanneer ik de pop- en push-stack gebruik, wordt dit gedeeld tussen functies. Natuurlijk zou ik lokale variabelen kunnen gebruiken, maar dan zou ik pointers moeten doorgeven als een extra parameter. Het tweede klassieke voorbeeld is te vinden in K&R’s “The C Programming Language” waar ze een getch()en ungetch()functies definiëren die een globale karakterbufferarray delen. Nogmaals, we hoeven het niet globaal te maken, maar is de toegevoegde complexiteit het waard als het behoorlijk moeilijk is om het gebruik van de buffer te verknoeien? Het derde voorbeeld is iets dat je zult vinden in de embedded ruimte onder Arduino-hobbyisten. Veel functies binnen de hoofdfunctie loopdelen allemaal de functie millis(), wat het moment is waarop de functie wordt aangeroepen. Omdat de kloksnelheid niet oneindig is, zal de millis()verschillenbinnen een enkele lus. Om het constant te maken, maak je een momentopname van de tijd voorafgaandaan elke lus en sla je deze op in een globale variabele. De tijdsnapshot is nu hetzelfde als wanneer deze wordt geopend door de vele functies.
  • Alternatieven:niet veel. Houd zoveel mogelijk vast aan lokale scoping, vooral in het begin van het project, in plaats van andersom. Naarmate het project groeit en als je denkt dat de complexiteit kan worden verlaagd met behulp van globale variabelen, doe dat dan, maar alleen als het voldoet aan de vereisten van punt twee. En onthoud dat het gebruik van lokale scope en het hebben van meer gecompliceerde code het minste kwaad is in vergelijking met het onverantwoord gebruiken van globale variabelen.

Antwoord 9, autoriteit 4%

U moet overwegen in welke context de globale variabele ook zal worden gebruikt. In de toekomst wil je dat deze code wordt gedupliceerd.

Bijvoorbeeld als u een socket binnen het systeem gebruikt om toegang te krijgen tot een bron. Wil je in de toekomst toegang hebben tot meer dan één van deze bronnen. Als het antwoord ja is, zou ik in de eerste plaats wegblijven van globals, dus een grote refactor is niet vereist.


Antwoord 10, autoriteit 2%

Het is een tool zoals elke andere die gewoonlijk te veel wordt gebruikt, maar ik denk niet dat ze slecht zijn.

Ik heb bijvoorbeeld een programma dat zich echt als een online database gedraagt. De gegevens worden in het geheugen opgeslagen, maar andere programma’s kunnen ze manipuleren. Er zijn interne routines die veel lijken op opgeslagen procedures en triggers in een database.

Dit programma heeft honderden globale variabelen, maar als je erover nadenkt, wat is een database dan een enorm aantal globale variabelen.

Dit programma is nu ongeveer tien jaar in gebruik in vele versies en het is nooit een probleem geweest en ik zou het zo weer doen.

Ik geef toe dat in dit geval de globale vars objecten zijn met methoden die worden gebruikt om de status van het object te wijzigen. Dus opsporen wie het object heeft gewijzigd tijdens het debuggen is geen probleem, omdat ik altijd een breekpunt kan instellen op de routine die de status van het object verandert. Of nog eenvoudiger, ik zet gewoon de ingebouwde logboekregistratie aan die de wijzigingen registreert.


11, Autoriteit 2%

Wanneer u constanten verklaart.


12

Ik zit hier in het “nooit”-kamp; als je een globale variabele nodig hebt, gebruik dan in ieder geval een singleton-patroon. Op die manier profiteer je van de voordelen van luie instantiëring en vervuil je de algemene naamruimte niet.

Other episodes