mplab C30 include funktion?

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
dangraf
Inlägg: 530
Blev medlem: 9 juni 2003, 15:30:56
Ort: göteborg

mplab C30 include funktion?

Inlägg av dangraf »

Hallå!

Jag har ett projekt där jag har mina c-filer i olika undermappar för att organisera upp det hela lite.
ex:
test_proj\: projektfiler, main fil mm.
test_proj\graphDisp: filer för hantering av grafisk display både header och c-filer

När jag programmerade C i skolan fick jag lära mig att om jag t.ex inkluderade en header fil i main-programet ex:
#include "graphDisp\graph.h"
som förhoppningsvis innehöll alla prototyper för de subrutiner som finns i *.c filerna så skulle kompilatorn själv leta upp dessa subrutiner i undermappen.
Vi använde oss av microsoft visual studio 6 till de projekten.

Nu när jag försöker göra samma sak i MPlab och C30 så fungerar det inte alls.
Det verkas som att man inte ens behöver skriva sina #include i c-filerna ifall man lägger till sina headers i projektet.

Själv skulle jag vilja att filerna i prjektet enbart användes för att lättare kunna hitta bland alla filerna, inte hur de ska inkluderas under kompileringen.

Problemet som uppstår för mig är att när jag har gemensamma filer (mellan olika projekt) så är jag intresserad av t.ex olika header filer och c-filer. Lägger jag till dessa i mitt projekt går inte kompileringen genom eftersom de är redan inkluderade i andra c-filer. (känner att min förklaring möjligen blev lite rörig).


Mina frågor är följande:
finns det någon standard för filer skall hanteras vid kompilering?
Är det någon som vet om man kan stänga av funktionen för att automatiskt inkludera filer i projektet i mplab?

// Daniel
Användarvisningsbild
Icecap
Inlägg: 26635
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Man brukar skriva något liknande:

#ifndef __DENNA_FIL_C__
#define __DENNA_FIL_C__

bla bla och mer bla bla

#endif // __DENNA_FIL_C__

Då kan den inkluderas 10^6 gånger utan problem, är den redan kompilerat en gång är #ifndef-satsen inte uppfylld och kompilern går vidare utan problem.
dangraf
Inlägg: 530
Blev medlem: 9 juni 2003, 15:30:56
Ort: göteborg

Inlägg av dangraf »

Jag vet.. har gjort det på en del ställen. Men jag skulle väldigt gärna vilja veta hur det fungerar/ ska fungera och varför.
Användarvisningsbild
Icecap
Inlägg: 26635
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Och det skrev jag också eller hur?

#ifndef __xxxx_x__ = om denna tag INTE är definierat
// Här kommer vi bara om ovanstående uttryck är uppfylld, alltså bara om __xxxx_x__ INTE är definierat.
#define __xxxx_x__ = OK, den är INTE definierat, gör det då nu då släpper vi komma hit igen.

Gör resten som ska göras här.

#endif = avsluter allt
sodjan
EF Sponsor
Inlägg: 43249
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Jag tolkade dangraf som hur det fungerar i MPLAB, inte hur dina IF's fungerar... :-)
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Inlägg av speakman »

Det funkar som så: i .c-filen har du själva funktionerna, och i .h-filen har du definitioner av de funktioner som vill "exportera" från din .c-fil.
Om du tänker dig att kompilatorn kompilerar .c-fil för .c-fil, vilket den faktiskt gör, istället för allt samtidigt (länkaren binder ihop allt i slutet) så är det lättare att förstå.

Om du har underkataloger med funktioner t.ex. dir/funcs.c + dir/funcs.h där .h-filen innehåller definitionen av funktionerna i .c-filen du tänkt använda.

Hela .h-filen som du lägger dina definitioner i skall omslutas enligt:

Kod: Markera allt

#ifndef __FUNCS_H
#define __FUNCS_H

/* en massa definitioner */

#endif
Då kommer den bara att inkluderas en gång oavsett om den inkluderas nästat ifrån andra includes osv.

I .c-filen i "roten" (vi kallar den main.c) vill använda funktionerna i .c-filen i underkatalogen "dir" så skriver du bara:

Kod: Markera allt

#include "dir/funcs.h"
Då kommer kompilatorn (som ju glömt vad den gjorde sist, den kompilerar som sagt en fil (objekt) i taget) att hämta dina definitioner av funktionerna i dir/func.h och sedan "godta" dessa oavsett om de verkligen existerar eller inte.

Det är nämligen inte förrän det sista momentet, länkningen, som det verkligen krävs att allt stämmer. Men det blir man ju onekligen varse om då.

För varje kompilerad .c-fil så blir det en objektfil. Dessa länkas slutligen ihop av just länkaren, och där är det viktigt att alla filer ingår:
./main.o
./dir/funcs.o

Länkningen resulterar slutligen i en .hex-fil el. dyl..

Många IDE (Integrated Development Environment), såsom AVR Studio och MPLAB, sköter hela den där biten åt dig; de .c-filer som finns i projektet anses ska länkas ihop. Precis som i Visual Studio 6.
Där ser man tyvärr inte hur det går till praktiskt, men om man provar att göra sin egen Makefile eller kompilerar och länkar helt manuellt så får man mer inblick i hur det går till "behind the scenes".

Dock gäller fortfarande principen kring .h-filerna.

Hoppas du blev lite klokare, annars får vi väl ta ett exempel. :)

EDIT: Behöver man köra #ifndef-"metoden" på .c-filer så har man gjort något generalfel nånstans. :)
Användarvisningsbild
Icecap
Inlägg: 26635
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

"Behöver man köra #ifndef-"metoden" på .c-filer så har man gjort något generalfel nånstans."

Inte nödvändigtvis. Man kan ha ett stort projekt där man kan testa de enstaka delarna för sig, dessa kan i sin tur behöva en gemensam fil för att fungera och då kan man köra allt utan att ändra en massa.
dangraf
Inlägg: 530
Blev medlem: 9 juni 2003, 15:30:56
Ort: göteborg

Inlägg av dangraf »

tack speakman, jag blev allt lite klokare :-) fick en del misstankar bekräftade..

I mina headers har jag fått skriva längst ner
#include "\folder\minfil.c"
för att kompilatorn skall hitta funktionerna i .c-filerna om de inte är med i själva projektet. Detta tycker jag är lite märkligt.

Jag skulle i vissa fall vilja veta vart include filen blir inkluderad.

Om jag t.ex skulle vilja försöka mig på lite objektorgenterad programmering i C, så vill jag ha möjlighet att definiera upp lite globala variabler som enbart skall vara tillgängliga för just den .c-filen. Om jag omsluter allt med #ifdef #endif så vet jag inte riktigt vart den inkluderades i koden (förutsatt att jag lagt till h filen i projektet) och helt plöttsligt kan mina globala variabler bli tillgängliga för alla andra c-filer om jag har otur vilket inte är så bra.
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Inlägg av speakman »

En tumregel är att i så stor mån som möjligt minimera användningen av globala variabler.
Man har i princip ingen, eller ytterst liten, användning av dom ö.h.t..
Ska man dessutom köra objektorientering i C så ser man ju till att hålla all info i objektet istället.
Det man däremot kan ha mer nytta av är objektlokala variabler (eller vad det nu heter), och dessa defineras med "static" längst upp i .c-filen. "static" innebär att variabeln endast är tillgänglig inom det "scope" den befinner sig i. Om du lägger den längst upp i en .c-fil, så gäller den endast för den .c-filen.
Vill man göra "riktiga" globala variabler så gör man på samma vis - definerar den längst upp i .c-filen (fast inte static då), och sedan gör man en likadan definition (deklaration) i .h-filen där man lägger till ett "extern" före definitionen.
Kontentan blir då att den (en annan) .c-fil som är intresserad av den globala variabeln, inkluderar den förra funktionens .h-fil och får därmed tillgång till definitionen av den. Eftersom den är "extern" kommer den att förvänta sig att länkaren kopplar ihop det namnet med en variabel som redan finns i ett annat objekt.
En kanske vanligare lösning för just globaler är att göra en "generell" .h-fil som inkluderas från samtliga moduler som vill ha tillgång till globala variaber. Däri ligger deklarationen, medans själva definitionen ligger i en lämplig .c-fil (main.c eller nått).

Men återigen - undvik globaler! Det går i princip alltid att lösa det på något annat vis, och då är det att föredra.

(Hm, fast man får vara lite förlåtande för inbäddade miljöer där minnet inte är obegränsat förstås. Fast objektorienterad C på uC's låter inte heller som en särskilt smidig idé.)

Icecap:
Jag brukar lösa alla "specialfall" genom att lägga en speciella targets i Makefile, varifrån jag sedan styr hur koden kompileras och länkas. T.ex. om jag vill testa vissa delar som du beskriver.
Jag strävar emot att källkoden ska ändras så absolut lite som möjligt beroende på vad den ska användas till.
Men det kanske inte fungerar i MPLAB, det vet jag inte.
Användarvisningsbild
Icecap
Inlägg: 26635
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Jag håller med om att variabler bör skyddas så väl det går.

'static' betyder INTE att den bara är inom scopen, det betyder att den plats INTE får användas till andra variabler som andra rutiner kan tänkas ha. Om man deklarerar en variabel som 'static' har den kvar samma värde när man kommer till rutinen igen, den är alltså 'fredat'. I andra fall kan kompilern snåla på minnet vid att återanvända platser vilket gör att man måste återställa variabler i en rutin innan man kan lita på deras värde.

Detta sker dock ofta och det är inte så ofta man behöver 'static'.

Lite OT: deklarerar man en variabel som 'volatile' betyder det att den kan ändras utanför den rutin som använder den (t.ex. i en ISR) och den MÅSTE då kollas, kompilern kan annars optimera den bort. Tänk följande:

Kod: Markera allt

volatile unsigned int Delay_Counter;

void Delay(unsigned int Delay_Value)
  {
  Delay_Counter = Delay_Value; // Set delay value
  while(Delay_Counter); // Wait untill it's zero
  }

void Timer_ISR(void)
  {
  if(Delay_Counter) Delay_Counter--;
  }
Nu är detta ett mycket enkelt exempel men om man lägger ihop ett antal uttryck (om detta eller hint eller TimeOut uppstår...) då kan kompilern optimera bort kollen av Delay_Counter, det hände mig i en kommunikationslänk. Efter jag deklarerade variablen som 'volatile' fungerade time-out på kommunikationen igen.

Och vad C-grejer har med MPLAB att göra har jag ingen aning om... för mig är MPLAB assembler.
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Inlägg av speakman »

Ang. MPLAB så var det dangraf som nämnde det i första inlägget. Jag vet inte alls vad det innebär.

Om static variables så kolla Wikipedia ang. bl.a. scopes.
En statisk variabel tilldelas alltid ett "eget" minnesområde, men sedan väljer man själv inom vilket "scope" man använder den, och den är endast giltig inom det scopet, samt dess eventuella "subscope".
Observera att artikeln benämner globala variabler som modulspecifika (endast för hela .c-filen), medans jag tidigare talade om "projektglobala" variabler.
I C finns ju ingen global variabel motsvarande i t.ex. Basic, eftersom objekt (.c-filer) kompileras var för sig och länkas först på slutet om man önskar.

Sedan skall kompilatorn ge en varning om man försöker nytta en oinitierad variabel, så jag vet inte i vilket sammanhang man skulle kunna råka ut för det.

"static" används också av kompilatorn för optimeringsskäl. Funktioner som *inte* exporteras, bara används lokalt i en .c-fil, bör även dom defineras som "static". Även detta för att förklara för kompilatorn ditt ändamål med funktionen. Kom fortfarande ihåg att kompilatorn för varje .c-fil (objekt) glömt vad den gjorde sist, och vet därför inte om en funktion anropas från andra objekt eller inte.

"volatile" var dock bra att det kom fram. Där kan man stypa lätt då kompilatorn inte gärna varnar om man inte använder det. Av naturliga skäl.
sodjan
EF Sponsor
Inlägg: 43249
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> ...för mig är MPLAB assembler...

MPLAB är en IDE där man **till exempel** kan utveckla ASM program.
Eller program i något av de andra supportade "tool sets" t.ex ASM30, C18 eller C30.
dangraf
Inlägg: 530
Blev medlem: 9 juni 2003, 15:30:56
Ort: göteborg

Inlägg av dangraf »

Jag får tacka för alla svar och tips! Givetvis går allt att lösa på olika sätt. Jag var kanske lite otydlig med vad jag egentligen var ute efter och det är hur MPLab fungerar. Jag försökte visa exempel på vart man jag stött på problem vilket kanske har rört till det en del.

Huvudfrågan som jag inte fått svar på ännu är:
Finns det en möjlighet så att man själv håller koll på sina include istälet för att MPlab gör det åt en genom projektfilerna?
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Inlägg av speakman »

Vad har egentligen MPLAB för inverkan på dina .c och .h-filer?
En "vettig" IDE ska inte beröra de alls, utan det är endast kompilatorn, och får man tolka sodjan fritt så tycks ju MPLAB inte vara bunden till någon särskild kompilator och därför inte hålla reda på dina .h-filer allt ö.h.t. (mer än kanske kolla vilka som används i projektet och lista dom i fillistan).
Men det låter mycket märkligt om IDE't påverkar kompileringen på något vis.
sodjan
EF Sponsor
Inlägg: 43249
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

MPLAB har en make-liknande funktion, det kanske kan ställa
till det lite när det gäller hur den väljer att bygga ett projekt...
Skriv svar