I den här artikeln kommer vi att diskutera pekoperatorer, pekare aritmetik och två situationer där pekare kan förbättra din kod.
supportinformation
Arbeta med pekervärden
Ändra pekare och referens
Det finns två värden associerade med en pekare. Den första är minnesadressen lagrad i själva pekaren, och den andra är informationen som lagras i denna minnesadress. För att ändra adressen som är lagrad i pekervariabeln använder du bara likhetstecknet:
RxByte_ptr = 0x40;
Använd en asterisk för att komma åt de data som lagras i pekarens adress. Detta fungerar både för läsning och skrivning.
ReceivedData = * RxByte_ptr; * TxByte_ptr = TransmitData;
Åtkomst till värdet som en pekare pekar på kallas referens, och en asterisk (när den används med pekare) kallas referensoperatören.
Få adressen till en variabel
En viktig detalj om användningen av pekare är operatören “C-riktning”; Symbolen för detta är &. Även om & är associerat med normala variabler snarare än pekare, ser jag det fortfarande som en “pekoperator” eftersom dess användning är nära relaterad till pekarimplementering.
När ett & placeras före ett variabelnamn använder programmet variabelns adress istället för variabelns värde.
Detta gör att du kan placera adressen till en variabel i en pekare, även om du inte har någon aning om var en variabel kommer att finnas i minnet. Användningen av & -operatören visas i följande kodavsnitt, som också fungerar som en sammanfattning av den grundläggande användningen av pekaren.
char DisplayChar; char TestingVariable; char * DisplayChar_ptr; DisplayChar = 0x41; DisplayChar_ptr = & DisplayChar; TestingVariable = * DisplayChar_ptr; * DisplayChar_ptr = 0x42; TestingVariable = DisplayChar;
Här är en steg-för-steg-förklaring av vad den här koden gör:
DisplayChar = 0x41;
DisplayChar-variabeln innehåller nu värdet som motsvarar ASCII “A”.
DisplayChar_ptr = & DisplayChar;
(DisplayChar_ptr) -pekaren innehåller nu adressen till DisplayChar-variabeln. Vi har ingen aning om vad den här adressen är, så vi vet inte numret som är lagrat i DisplayChar_ptr. Vi behöver inte heller veta; Denna kompilators jobb är inte vårt.
TestingVariable = * DisplayChar_ptr;
TestingVariable har nu värdet på DisplayChar-variabeln, dvs. 0x41.
* DisplayChar_ptr = 0x42;
Vi använde pekaren för att ändra värdet som lagrats i adressen som motsvarar DisplayChar-variabeln; nu är det 0x42, det här är ASCII ‘B’.
TestingVariable = DisplayChar;
TestingVariable har nu värdet 0x42.
Pekare aritmetik
Ofta har en C-variabel ett variabelt värde och pekervariabler är inget undantag. Vanliga aritmetiska operationer som används för att ändra värdet på en pekare är addition (till exempel TxByte_ptr = TxByte_ptr + 4), subtraktion (TxByte_ptr = TxByte_ptr – 4), inkrement (TxByte_ptr ++) och minskning (TxByte_ptrtr ++) där samma data har samma. Så länge det är möjligt att ta bort en markör från en annan. Du kan dock inte lägga till en pekare till en annan pekare.
Pekarens aritmetik är inte så enkelt som det verkar. Anta att du har en pekare med en lång datatyp. Du felsöker lite kod och du gör för närvarande ett enda pass från en rutin som ökar den här pekaren upprepade gånger. Observera att pekarens värde inte ökar med varje steg i observationsfönstret. Vad händer här?
Om du inte kan tänka på svaret lätt, bör du spendera lite mer tid på att tänka på pekarnas natur. Pekaren i den här koden används med långa variabler, dvs. variabler som förbrukar fyra byte minne. När du ökar pekaren vill du inte att pekarens värde ska öka med en position i minnet (förutsatt att minnet är organiserat i byte). Istället vill du att den ska ökas med fyra minnesplatser för att visa nästa långvariabel. Kompilatorn vet detta och ändrar pekarens värde därefter.
Detsamma gäller när du lägger till eller subtraherar ett tal från pekaren. Adressen som lagras i markören ökar eller minskar inte nödvändigtvis detta nummer; istället ökar eller minskar detta antal multiplicerat med storleken i byte av pekardatatypen.
Pekare och matriser
Pekare och sekvenser är nära besläktade. När du deklarerar en matris skapar du alltid en fast pekare som innehåller matrisens startadress och indexnotationen som vi använder för att komma åt elementen i en matris kan också användas med pekare.
Anta till exempel att du för närvarande har en teckenpekare som heter TxBuffer med adressen 0x30. Kodavsnittet nedan visar två likvärdiga sätt att komma åt data på adressen 0x31.
TxByte = * (TxBuffer + 1); TxByte = TxBuffer[1];
När används pekare?
I det här avsnittet vill jag kort nämna två kodningssituationer som kan dra nytta av användningen av pekare och som är särskilt relevanta för inbäddade applikationer.
Pekare kontra matris
Den första följer naturligtvis diskussionen i föregående avsnitt. Pekare ger en alternativ metod för att manipulera data som lagras i ett arrayformat. Pekaren kan vara mer intuitiv eller mer användbar i ett visst rutinmässigt sammanhang.
I vissa fall kan dock en pekarbaserad applikation ge snabbare kod. Som jag förstår det var detta mer sant tidigare innan kompilatorerna var extremt sofistikerade och hade så omfattande optimering. Men i samband med integrerad utveckling tror jag att det finns vissa situationer där pekare kan uppnå en märkbar förbättring av körhastigheten. Om du verkligen försöker få det minsta antal klockcykler som krävs för att köra en viss kod är pekare värda ett försök.
Vidarebefordra pekare till funktioner
Omfattande användning av funktioner hjälper dig att skriva organiserad och modulär kod. Detta är bra, även om C inför en begränsning som kan vara konstig i vissa fall: en funktion kan bara ha ett returvärde. Med andra ord, Förändra Endast en variabel om du inte använder en pekare.
Denna teknik fungerar enligt följande:
- Lägg till en pekare som en av funktionens ingångar.
- Använd & -operatören för att skicka adressen till en variabel till funktionen.
- Inne i funktionen blir variabelns adress pekarens värde och funktionen använder referensoperatören för att ändra värdet på den ursprungliga variabeln.
- Även om den ursprungliga variabeln inte ändras direktMed hjälp av ett returvärde antar koden som följer funktionen att variabelns värde ändras.
Här är ett exempel:
#define STEPSIZE 3 void IncreaseCnt_and_CheckLED (char * Count) { * Count = * Count + STEPSIZE; si (LED == VERDADERO) volver VERDADERO más falso retorno; } int main () { char RisingEdgeCount = 0; bit LED_State; ... ... LED_State = IncreaseCnt_and_CheckLED (& RisingEdgeCount); ... ... }
resultat
Jag hoppas att du har en tydlig uppfattning om vad pekare är och hur du kan börja arbeta med dem i din firmware för C-språk. Kommentarer nedan om det finns aspekter av inbäddad C som du vill att vi ska diskutera i framtida artiklar.