Programmeringsstil i C
Programmeringsstil i C
Hej
Hur brukar ni strukturera upp era program/projekt i C? Finns det några allmänna standarder för att struktuerar C program som går igen i varje seriöst/professionellt projekt?
Försöker ni göra det objektorienterat så mycket som möjligt eller?
Gick en AVR kurs där läraren förespråkade att man för t.ex. en display skapar en display struct typ och sedan tillhörande funktioner till denna där man bifogar en instansierad display med varje funktionsanrop.
Tack...
Hur brukar ni strukturera upp era program/projekt i C? Finns det några allmänna standarder för att struktuerar C program som går igen i varje seriöst/professionellt projekt?
Försöker ni göra det objektorienterat så mycket som möjligt eller?
Gick en AVR kurs där läraren förespråkade att man för t.ex. en display skapar en display struct typ och sedan tillhörande funktioner till denna där man bifogar en instansierad display med varje funktionsanrop.
Tack...
Det är väl där som det kan skilja sig en del.
Efter vad jag vet finns det inte en standart men självbevarelsesdriften gör att man strukturerar ordentligt.
Nu frågar du på 'C' men användar klasser..... 'class' tillhör C++!
Jag gillar personligen C++ just för att man kan packetera klasser osv, det ger ett variabelskydd som är bra.
Jag försöker att göra alla hårdvarugrejer på ett sätt som ger mig en standart att anropa, jag har t.ex. en Send2LCD, Send2UART1 osv som tar strängar och skickar ut dom via bufferter med interruptstyrning osv, detta ger mig en standart som tar samma sorts data oavsett vilken enhet som ska nyttja dom.
Efter vad jag vet finns det inte en standart men självbevarelsesdriften gör att man strukturerar ordentligt.
Nu frågar du på 'C' men användar klasser..... 'class' tillhör C++!
Jag gillar personligen C++ just för att man kan packetera klasser osv, det ger ett variabelskydd som är bra.
Jag försöker att göra alla hårdvarugrejer på ett sätt som ger mig en standart att anropa, jag har t.ex. en Send2LCD, Send2UART1 osv som tar strängar och skickar ut dom via bufferter med interruptstyrning osv, detta ger mig en standart som tar samma sorts data oavsett vilken enhet som ska nyttja dom.
Man ska alltid försöka skriva modulärt med så få beroenden som möjligt mellan modulerna. Då får man återanvändbar och lättestad kod. Om jag skriver kod för en LCD t.ex, så gör jag en lcd.c och en lcd.h.
Sen brukar döpa funktionerna i mina moduler på detta sätt:
LCD_Init();
LCD_Write(char c);
LCD_Goto(char pos);
I h-filen brukar jag lägga definitioner som t.ex:
#define LCD_ROWS 2
Jag kunde så klart skicka med såna parametrar med LCD_Init(), men eftersom man oftast bara har en LCD i ett projekt så blir det effektivare att "hårdkoda" det på detta sätt.
Om jag har en global variabel, typ vilken kolumn LCD:ns markör ligger på, så brukar jag göra så här i c-filen:
unsigned char _LCD_Column;
och så här i h-filen:
#define LCD_GetColumn() _LCD_Column
#define LCD_SetColumn(x) _LCD_Column = x
extern unsigned char _LCD_Column;
Detta kostar inte mer kodutrymme, men gör interfacet mot din kod abstrakt, så om man senare t.ex. vill läsa kolumnsiffran från själva LCD-modulen istället för att hålla reda på den själv, så går det lätt att fixa utan att någon annan kod påverkas.
På samma sätt kan man göra om LCD_SetColumn() till en funktion och låta den skicka över kolumnsiffran till LCD-modulen automatiskt.
Resultatet blir inte alltför olikt ett objektorienterat programmeringssätt.
Om man har nått "objekt" som används flera gånger, så lägger man lämpligen alla variabler i struct och gör precis som din lärare sa. Dock "kostar" det ganska mycket kod att skicka med parametrar till funktionerna, iaf om man använder PIC med 3-byte pekare och parametrarna läggs på stacken.
Sen brukar döpa funktionerna i mina moduler på detta sätt:
LCD_Init();
LCD_Write(char c);
LCD_Goto(char pos);
I h-filen brukar jag lägga definitioner som t.ex:
#define LCD_ROWS 2
Jag kunde så klart skicka med såna parametrar med LCD_Init(), men eftersom man oftast bara har en LCD i ett projekt så blir det effektivare att "hårdkoda" det på detta sätt.
Om jag har en global variabel, typ vilken kolumn LCD:ns markör ligger på, så brukar jag göra så här i c-filen:
unsigned char _LCD_Column;
och så här i h-filen:
#define LCD_GetColumn() _LCD_Column
#define LCD_SetColumn(x) _LCD_Column = x
extern unsigned char _LCD_Column;
Detta kostar inte mer kodutrymme, men gör interfacet mot din kod abstrakt, så om man senare t.ex. vill läsa kolumnsiffran från själva LCD-modulen istället för att hålla reda på den själv, så går det lätt att fixa utan att någon annan kod påverkas.
På samma sätt kan man göra om LCD_SetColumn() till en funktion och låta den skicka över kolumnsiffran till LCD-modulen automatiskt.
Resultatet blir inte alltför olikt ett objektorienterat programmeringssätt.
Om man har nått "objekt" som används flera gånger, så lägger man lämpligen alla variabler i struct och gör precis som din lärare sa. Dock "kostar" det ganska mycket kod att skicka med parametrar till funktionerna, iaf om man använder PIC med 3-byte pekare och parametrarna läggs på stacken.
Intressant ämne! Jag undrar detsamma, i hur stor grad man använder strukturer och försöker "efterlikna" objektorienterad programmering när man skriver större/modulära C-projekt till exempelvis de mindre µC (PIC/AVR 8-bitare).
Imorgon börjar jag en kurs i C-programmering som sägs vara tuff, det ska bli intressant att veta hur föreläsaren tycker att man ska göra. Jag tror förvisso den är riktad till större plattformar än 8-bitare, men C är alltid C.
Imorgon börjar jag en kurs i C-programmering som sägs vara tuff, det ska bli intressant att veta hur föreläsaren tycker att man ska göra. Jag tror förvisso den är riktad till större plattformar än 8-bitare, men C är alltid C.
> Jag tror förvisso den är riktad till större plattformar än 8-bitare, men C är alltid C.
Jo, sant å sätt och vis.
Men ju "större" plattform, ju mindre behöver man ta hänsyn till själva plattformen och istället skriva mer "ren" C.
På mindre plattformar (där PIC/AVR nog får räknas in) är det inte alltid bara att skriva sin C-kod "by-the-book"...
Jo, sant å sätt och vis.
Men ju "större" plattform, ju mindre behöver man ta hänsyn till själva plattformen och istället skriva mer "ren" C.
På mindre plattformar (där PIC/AVR nog får räknas in) är det inte alltid bara att skriva sin C-kod "by-the-book"...

Ja, det "göttiga" med C är att det är tillräckligt hårdvarunära för att kunna skriva optimerat för plattformen.
Men! Å andra sidan är det alltid bra att kunna strukturera sitt projekt, möjligtvis på bekostnad av lite kodutrymme och kanske en smula prestanda.
Skräckexemplet är väl när man helt plötsligt sitter där med 50 globala variabler bara för att man implementerat fem regulatorer, och de logiska namnen börjar ta slut...
Som vanligt, lagom av varje är bäst!
Men! Å andra sidan är det alltid bra att kunna strukturera sitt projekt, möjligtvis på bekostnad av lite kodutrymme och kanske en smula prestanda.
Skräckexemplet är väl när man helt plötsligt sitter där med 50 globala variabler bara för att man implementerat fem regulatorer, och de logiska namnen börjar ta slut...

Som vanligt, lagom av varje är bäst!
- JimmyAndersson
- Inlägg: 26586
- Blev medlem: 6 augusti 2005, 21:23:33
- Ort: Oskarshamn (En bit utanför)
- Kontakt:
> Men! Å andra sidan är det alltid bra att kunna strukturera sitt projekt,...
Vilket ju inte är unikt för C på något vis.
Om man t.ex utnyttjar MPASM/MPLINK ordentligt, så går det bra
att skiva väl strukturerad kod, men lokala variabler, separate moduler,
återanvändbar kod, relokerbar kod, dynamisk allokering av minne o.s.v.
Vilket ju inte är unikt för C på något vis.
Om man t.ex utnyttjar MPASM/MPLINK ordentligt, så går det bra
att skiva väl strukturerad kod, men lokala variabler, separate moduler,
återanvändbar kod, relokerbar kod, dynamisk allokering av minne o.s.v.
En googling på C-Programming style gav dessa dokument bl.a.
http://sel.gsfc.nasa.gov/website/docume ... 94-003.pdf verkar vara tämligen heltäckande.
http://faculty.cs.tamu.edu/welch/teaching/cstyle.html
http://www.w3.org/Library/User/Style/
http://sel.gsfc.nasa.gov/website/docume ... 94-003.pdf verkar vara tämligen heltäckande.
http://faculty.cs.tamu.edu/welch/teaching/cstyle.html
http://www.w3.org/Library/User/Style/
Jag tycker det är estetiskt roligt att få till ett välordnat program. När allt har ordning blir oftast funktionen mer stabil som sagt.
Tack för länkarna de ser lovande ut. Sökte själv utan resultat.
Tack för länkarna de ser lovande ut. Sökte själv utan resultat.
Om man skickar med adressen till displayobjektet då? Menar du att även 1 parameter kostar? Lägger kompilatorn dessa parametrar på stacken tillsammans med PC? Hur gör den det då man med vanlig assembler inte kan komma åt stacken direkt?Om man har nått "objekt" som används flera gånger, så lägger man lämpligen alla variabler i struct och gör precis som din lärare sa. Dock "kostar" det ganska mycket kod att skicka med parametrar till funktionerna, iaf om man använder PIC med 3-byte pekare och parametrarna läggs på stacken.
Det finns några punkter man bör tänka på:
Modulärt
Lättläst
Abstraktion
Dokumenterat
Modulärt för att det gör det lättare att uppgradera koden från säg uppgift eller chip X till Y osv..
Dessutom underlättar det felsökning enormt dåd du kan ringa in problem.
Lättläst innebär att göra så att man förstår det vid första anblicken. Behöver inte nödvändligtvis vara superkonskvent.
Abstraktion så att om dina I/O portar osv flyttar på sig så slipper du skriva om koden.
Dokumenterat så alla som inte vet vad bit 5 på port 0xFE gör kan förstå det. Eller vad tr_tmp ^= 0x98; är bra för.
Modulärt
Lättläst
Abstraktion
Dokumenterat
Modulärt för att det gör det lättare att uppgradera koden från säg uppgift eller chip X till Y osv..
Dessutom underlättar det felsökning enormt dåd du kan ringa in problem.
Lättläst innebär att göra så att man förstår det vid första anblicken. Behöver inte nödvändligtvis vara superkonskvent.
Abstraktion så att om dina I/O portar osv flyttar på sig så slipper du skriva om koden.
Dokumenterat så alla som inte vet vad bit 5 på port 0xFE gör kan förstå det. Eller vad tr_tmp ^= 0x98; är bra för.
Enligt länkarna från TomasL verkar det inte finnas någon vedertagen standard för funktionsprologer ("function prolog"), likt det som finns i t.ex. javadoc? Eller det är upp till varje kompilatorpaket att välja standard, om det ens finns ett system för att generera dokumentation?
Jag menar något i stil med detta:
Jag menar något i stil med detta:
Kod: Markera allt
/*
* This function calculates the metric equivalent in centimeters
* of the values in the variables feet and inches.
*
* @param feet feet part of height
* @param inches inches part of height
* @return height in centimeters
*/
float calculateHeight( int feet, int inches )
{
...
}