C variabele declareren ?

Ik moest hier wel 10 keer kijken wat er nu gebeurt.

Maar als ik het goed begrijp:
- Je main.c bevat enkel include files.
- De include files definieren variabelen en funkties.
- Dan hoef je alleen main.c te kompileren. Dus feitelijk krijg je een enkele compile module waar dmv de invludes alle code in zit.

Dat kan. Maar
- Is nogal ongebruikelijk.
- Want je hebt geen enkele afscherming meer. Alle internals van elke module worden automatisch globaal.

Normaal wordt alles verdeeld over meerdere .c files. Die ook apart gecompileerd kunnen worden. Zodat je kunt kiezen welke stukken 'publiek' worden en welke stukken 'lokaal' binnen de module blijven.
Maar die mogelijkheid gooi je dan overboord. Mij best, maar dat zou ik niemand aanraden.

De #ifndef include guards heb je in zo een systeem trouwens niet nodig. Dat helpt alleen als je dezelfe file meerdere keren in de lijst van main.c zet. En dat is dan duidelijk een vergissing die gecorrigeerd moet worden

trix

Golden Member

allen dank voor de input.
er zijn meerdere wegen die naar rome leiden. maar er zal er maar 1 het snelst zijn, of het korts, of het goedkoopst.
hier zullen ook wel meerdere wegen zijn. maar er zal er maar 1 het minst geheugen innemen, duidelijkst zijn of het snelst zijn.

het is maar net wat je zelf het belangrijkst vind in jou toepassing.

ik moet ergens meerdere variabelen van het een naar het ander tabblad (ik blijf het voor de duidelijk tabblad noemen) meenemen.
om het concreet te maken, ik heb 8 stappenmotoren die ik moet "homen" met de daar bij behorende correctie (t.g.v. mechanisch constructie). dat "homen" doe ik in een appart tablad waar uit ik dus 1 van de 8 variabelen moet meenemen naar een ander tabblad b.v. movement_X_axle. en een andere variabele naar tabblad: movement_Y_axle.

eigenwijs = ook wijs

Op 29 maart 2021 18:45:08 schreef big_fat_mama:
Maar dan spreken we over projecten van vele duizenden regels code, dat is voor mij niet relevant. En zo is het voor de grote meerderheid alhier, lijkt me.

Het project waar het hier om gaat, dat van trix, dat groeit hem boven de pet. Te veel code, niet meer te bevatten, niet te onderhouden of "niet af te maken" als de grens net wat eerder bereikt wordt.

Sommige best-practises aanleren op zo'n moment is helemaal niet verkeerd.

Het probleem waar jij een keer tegenaanloopt is dat je een variabele in functie X gebruikt, waarbij die (viavia) functie Y aanroept die ook een variable nodig heeft, waar zeg maar dezelfde grootheid in hoort te staan. Logisch gezien kies je dezelfde naam. Voeg je de variabele dan onder dezelfde naam toe aan je include, dan krijg je een hint van de compiler dat het niet klopt. Maar op het moment dat je dus tegelijkertijd een keer de fout maakt om te vergeten de declaratie toe te voegen, dan gaat ie gewoon de andere variabele gebruiken.... De vraag is niet OF dat gaat gebeuren, maar wanneer.... :-)

Jou stijl heeft wat weg van Fortran. Leren programmeren in Fortran?

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
EricP

mét CE

maar er zal er maar 1 het minst geheugen innemen, duidelijkst zijn of het snelst zijn.

DAT valt dus wel mee. Optimizers zijn best slim doorgaans. Het is helemaal niet raar dat verschillende stukjes source die hetzelfde doen tot dezelfde object code voeren.

ik moet ergens meerdere variabelen van het een naar het ander tabblad (ik blijf het voor de duidelijk tabblad noemen) meenemen.
om het concreet te maken, ik heb 8 stappenmotoren die ik moet "homen" met de daar bij behorende correctie (t.g.v. mechanisch constructie). dat "homen" doe ik in een appart tablad waar uit ik dus 1 van de 8 variabelen moet meenemen naar een ander tabblad b.v. movement_X_axle. en een andere variabele naar tabblad: movement_Y_axle.

Tab bladen zeggen me niet zoveel. Dat is geen gebruikelijke constructie binnen C - en dus is er geen context voor gedefinieerd.

In principe is het simpel: een variable is niet meer zichtbaar buiten de scope waarbinnen die is gedefinieerd. Een tabblad is geen 'scope' in deze context. Een (sub) funtion kan dat zijn. Een file zou ook nog kunnen (strikt genomen is het dan een global waarvan de rest van de wereld niet weet dat die er is. En er dus in principe ook niet aan komt). En daarnaast kun je ze echt global maken.
Het klinkt alsof de oplossing is om een array met 8 entries te maken van structs met members voor je X en Y correctie. Het lijkt erop dat 'alles' die dingen gebruikt, dus, hoe ranzig ook, dat is wel iets om global te doen (om te voorkomen dat je eindeloos parameters aan het doorgeven bent).
Nogmaals, de context van een tab blad is binnen C niet gedefinieerd. Als zodanig de scope van een tabblad ook niet...

Jou stijl heeft wat weg van Fortran. Leren programmeren in Fortran?

[[ off topic! ]] Grijns. Nee, nooit Fortran gedaan - wel Basic, ook professioneel - jaja, Business Basic en Thoroughbred en zo - Basic was toch afgeleid van Fortran?

Als ik graag variabelen globaal declareer, en allemaal tezamen ergens in het begin, dan is dat misschien een restant van een cursus Cobol die ik ooit volgde - in COBOL heb je een aparte sectie met alle declaraties, en geen locale variabelen (ik denk dat C daarmee de eerste was). Maar noch Fortran noch Basic noch Cobol kennen include files :)

@Topicstarter: ik ga graag mee met de analyses. Dit project wordt u te complex, het is misschien een goed idee om helemaal opnieuw te beginnen, met een nieuwe stijl en een nieuwe aanpak. Wie weet zelfs zonder "tabbladen" want die maken het inderdaad alleen maar wolliger en dus minder vatbaar - of, zoals iemand zeer fraai verwoordde - "behapbaar".

hoe beter de vraag geschreven, zoveel te meer kans op goed antwoord
trix

Golden Member

tabblad, bedoel ik natuurlijk een .h en .c combinatie mee.

de complexiteit valt wel mee, het is veel dat wel, maar dat wil niet automatisch zeggen complex. ja nu even wat betreft doorgeven van variabele, omdat ik het nog steeds een hoep gedoe vind voor iets wat in mijn ogen veel simpeler kan zijn (in mijn toepassing).
maar als het zo moet dan doen we dat :)

edit: het is niet complex omdat "de machine" veel dingen na elkaar doet. die je eigenlijk per stuk kan bekijken, er worden natuurlijk wel variabele door gegeven.

[Bericht gewijzigd door trix op 29 maart 2021 21:48:26 (19%)]

eigenwijs = ook wijs

Op 29 maart 2021 21:05:40 schreef big_fat_mama:
en geen locale variabelen (ik denk dat C daarmee de eerste was).

Ik denk dat het "pascal" was. Voor Pascal vind ik " begin jaren zeventig" en voor C 1973 als start-datum. D'r was ook nog een ander taaltje, net eerder met pascal-achtige structuur.

Maar even googlend: als "voorloper van Pascal" vond ik "algol60" (uit 1960! Duh!) waar ook al locale variabelen in zitten! Zie wikipedia.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Tab bladen zeggen me niet zoveel.

TS werkt met Atmel studio.
En de editor van Atmel studio gebruikt Tab-bladen per file.

Op 29 maart 2021 21:05:40 schreef big_fat_mama:
[...]
Maar noch Fortran noch Basic noch Cobol kennen include files :)

Fortran 77 kent het include statement, dat gebruikten wij (lang geleden) voor de COMMON blocks (globale variabelen).
Fortan kent wel lokale variabelen, alleen zijn ze alle (om een 'C' equivalent te gebruiken) static.
Dus als je een subroutine/functie aanroept voor de tweede keer dan hebben alle lokale variabelen nog de waardes waarmee je hem de vorige keer hebt verlaten).

De moderne interpretatie van "locale variabele" is dus dat ie op de stack zit en dus recursie mogelijk is. In die zin zijn de oude fortran functie-scope-static-variabele niet "locaal". Je moet je ook realiseren dat Fortran66 de standaard was om tig jaren fortran "troep"(*) te standaardiseren. Fortran77 werd een aardig moderne taal. En fortran90 was weer een forse update.

(*) troep als in: verschillende compilers doen eea net allemaal verschillend.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Hewlett

Honourable Member

Computer architecturen in de vroege tijd van Fortran kenden geen stack, dat was ook geen vereiste voor de computer toepassingen in die tijd en deze legacy is in de latere incarnaties van Fortran gebleven. Algol 60 was de eerste programmeertaal met lokale variabelen, geneste functies en recursie.

HamRadio PA2HK // Keep Calm and Carry On.

Op 30 maart 2021 10:25:26 schreef Hewlett:
Algol 60 was de eerste programmeertaal met lokale variabelen, ....

Als Fortran geen lokale variabelen heeft, wat is dat de functie van een COMMON block in Fortran ?
Dat het geen stack variabele is wil nog niet zeggen dat het een geen lokale variabele is.
Ik heb overigens gebruik gemaakt van Fortran IV, Fortran 77 en RatFor (Fortran precompiler: geen GOTO's en Regelnummers meer).

Tsja, zelfs de definitie van "lokale variable" durft verschillen van de ene taal (of zelfs compiler) naar de andere.

Computer architecturen in de vroege tijd van Fortran kenden geen stack

Deze zin vind ik uiterst verwarrend. Wat wordt bedoeld met "computerarchitectuur"? De vroegste processors die ik kende hadden allemaal wel een stack, hoewel soms stevig beperkt (bv. 6502: 1 pagina, hardcoded op 01xx, dacht ik, of was het 02xx...)

Mogelijks wordt er bedoeld dat er binnen de vroege programmeertalen geen plaatselijke stack bestond?

[Bericht gewijzigd door big_fat_mama op 30 maart 2021 13:32:11 (66%)]

hoe beter de vraag geschreven, zoveel te meer kans op goed antwoord
hennep

Golden Member

Op 30 maart 2021 10:25:26 schreef Hewlett:
Algol 60 was de eerste programmeertaal met lokale variabelen

De taal Plankalkül kent alleen maar locale variabelen!
De eerste plannen om de taal Plankalkül te ontwikkelen zijn van Konrad Zuse en zijn gemaakt rond 1942. De makers van Algol waren bekend met het werk van Zuse dus Algol verdient zeker niet de eerste plaats :-)

Op 30 maart 2021 13:29:03 schreef big_fat_mama:
Deze zin vind ik uiterst verwarrend. Wat wordt bedoeld met "computerarchitectuur"? De vroegste processors die ik kende hadden allemaal wel een stack, hoewel soms stevig beperkt (bv. 6502: 1 pagina, hardcoded op 01xx, dacht ik, of was het 02xx...)

Haha! Dan ben je te jong! :-) (Is dat de laatste tien jaren al eens tegen je gezegd?)

Computers van VOOR de microprocessor, maar NIET de PDP11 (en voorgangers?) zouden heel goed (ik ben eigenlijk ook te jong) geen stack gehad kunnen hebben.

Om een call te doen, werd wel dan de huidige PC op het adres van de subroutine gezet en vervolgens gesprongen naar het volgende adres. Om een return te doen haalde je dan in de subroutine de waarde op van het eerste adres van de subroutine en sprong daarnaartoe.

De PDP had genoeg mooie adresseringsmodes dat je daar prima een stack mee kon bouwen. 1 register werd vanaf het begin als stack pointer gepropageerd, maar hij was eigenlijk helemaal niet speciaal. Waar je in de 6502 een PHA (push A( instructie had, moet je op de PDP gewoon een mov R3, -(R6) doen om een register op de stack te pushen, en mov (R6)+, R3 om hem weer terug te halen (pop). (omdat gebruikelijk is dat de stack naar beneden GROEIT is een decrement dus GROEIEN van de stack).

Maar de IBM's van die tijd kunnen best wel eens "geen stack support" gehad hebben. Dan moet je het helemaal zelf implementeren als je dat wilt.

Ik heb in 1985 met een Pr1me 9955 (en 850 en 450?) te maken gehad. Dat ding had ook nauwelijks stack support. Bedoeld om Fortran te draaien.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

het kan aan mij liggen, maar variabele declareren in header files lijkt me echt NOT done.

Als je een globale variabele hebt die je in andere c files nodig hebt dan declareer je die in de c (position.c) file als

code:

uint8_t homePositie;

en in de bijbehorende header file (position.h) als

code:

extern uint8_t homePositie;

vervolgens doe je in elke C file waar je die variabele nodig hebt een #include "position.h"

Enerzijds respect voor je doorzettings vermogen ,maar ik krijg ook zo'n jeuk van alle coding rules die je breekt :)

C (en C++) maakt onderscheid tussen een declaratie en een definitie.
Precies volgens je voorbeeld:

De extern.. is de declaratie en die gaat in de header file.
De uint.. is de definitie die gaat in de .c file.

Dus declaraties gaan wel degelijk in de header files. :)

Enerzijds respect voor je doorzettings vermogen ,maar ik krijg ook zo'n jeuk van alle coding rules die je breekt

Dank voor het respect, en veel pret gewenst met je jeuk ;) Reeds eerder stelde ik dat ik niet wakker lig van "coding rules", toch zeker niet in een project waar niemand anders aan te pas komt. Ik geef grif toe dat het me niet zou meevallen om in te stappen in een team dat grote C-projecten beheert, maar dat is dan ook helemaal mijn ambitie niet, ik acht er mezelf trouwens niet bekwaam toe.

Eigenlijk zou ik liefst een enkele mijn_project.c schrijven en compileren, en dat heb ik ooit wel gedaan; maar zo'n kleine zaakjes doe ik tegenwoordig in python. Een grote klus is eigenlijk nog steeds een enkel bestand, alleen deel ik het op in includes, met in de main nog enkel een init en een hoofdlus (arduino-klokje klept luidkeels!!) en die bestaan beide uit een reeks #includes.

Ongebruikelijk, allicht, maar voor mij werkt het. QED. En geen gehannes met dubbele declaraties en geen discussies over het geslacht der engelen of het onderscheid tussen definities en declaraties :) ! En geen aparte header-files nodig, evenmin. Hoe simpeler hoe beter, voor deze jongen!

Haha! Dan ben je te jong! :-) (Is dat de laatste tien jaren al eens tegen je gezegd?)

Hahaha, goeie bak! En helemaal raak, ook. Ik heb altijd al veel goeds gehoord over de pdp-7/pdp-11 maar heb er nooit eentje onder handen gehad. Dat codefragmentje herinnert me aan mijn korte contretemps met de 68000, die had ook een zee van algemene registers waarmee men alle kanten uit kon. Ik blijf me wel vragen stellen bij het behandelen van interrupts: daar heb je toch normaliter een gebeuren in de hardware (IRQ) dat acties triggert die op software gelijken - program counter de stack op, minimaal, en wellicht ook het statusregister.

hoe beter de vraag geschreven, zoveel te meer kans op goed antwoord

Ik doelde ook op Trix bfm. En val niet over hoofdletter gebruik of spaties, wel over includes in functies:)

interrupts: daar heb je toch normaliter een gebeuren in de hardware (IRQ) dat acties triggert die op software gelijken - program counter de stack op, minimaal, en wellicht ook het statusregister.

Meestal wel ja, maar hoeft niet.
ARM bijvoorbeeld heeft een aparte set registers voor interrupts. Die switcht gewoon van register set. Veel sneller en geen stack nodig.

Niet dat een ARM geen stack heeft trouwens. Die heeft daar juist heel krachtige features voor aan boord.

TMS9900 is ook een leuk voorbeeld. Geen stack, alle registers in ram en alleen een WP pointer.

Op 30 maart 2021 18:33:08 schreef rew:
Computers van VOOR de microprocessor, maar NIET de PDP11 (en voorgangers?) zouden heel goed (ik ben eigenlijk ook te jong) geen stack gehad kunnen hebben.

Ze hadden wel een stack, maar geen user-stack. Werd dus alleen gebruikt voor de program counter. Kijk naar de PIC 16 reeks: alleen een hardware stack voor de PC, geen user stack. Sommige C compilers voor die reeks gebruiken dus gewoon een stukje geheugen voor lokale variabelen, geen stack en met een call-tree zoeken ze uit of twee functies niet overlappen: dan kunnen ze dezeldde geheugenlokaties gebruiken voor de lokale variabelen.

De PDP 11 reeks (mee gewerkt tot in de jaren 80) had trouwens een heel mooie symmetrische structuur. Motorola heeft daar met de 68000 reeks het nodige van afgekeken.

Ja de PDP11 had 2 operands. 3 bits voor het register, 3 bits voor de adresseringsmode dus totaal 12 bits voor de operands. Vervolgens hou je maar 4 bits per instructie over voor de eigenlijke instructie. Net te weinig.

Voor de 68000 hadden ze prachtig 5 bits voor register-adressering, 3 bits voor adresmode kunnen doen, blijven er 16 bits voor de opcode over.... Of drie operands en 8 bits voor de opcode. Volgens mij hebben ze dat net niet helemaal gedaan, toch? Ik ben begin jaren tachtig een tijdje bezig geweest om m'n eigen processor te ontwerpen. Totdat m'n pa een keer een 68000 handleiding mee naar huis nam. Whoa, die gasten hebben het vaker gedaan. Dat ziet er netjes uit! Daar kan ik nooit aan tippen, laat maar ik geef het op.

Voor interrupts heb je, als je meer registers hebt dan een 8086 of 6502 ongeveer twee opties: Ofwel je hebt in hardware een schaduw registerset zoals deKees al aangeeft. De andere optie is: Laat de software het maar doen. Dan pusht de hardware alleen de PC en mogelijk het statusregister op de stack en mag je de rest (alles wat je nodig hebt) zelf doen.

Dit levert natuurlijk leuke bugs op als je in je hoofdprogramma "zelden" register Rx gebruikt terwijl de interrupt routine... idem: zelden Rx gebruikt en die vergeten is om op de stack te bewaren...

Edit:

Ik vind het "oude computer architecturen" onderwerp best interessant, maar eigenlijk helpen we Trix daar geen zier mee....

* Bij het programmeren KAN je er altijd een zooitje van maken.
* Er zijn "programmeerstijl" regels die je niet MOET volgen maar dat is uiteindelijk toch echt beter om je er over het algemeen aan te houden: Ze helpen je om het overzichtelijk te houden.

Voorstel:
* Begin met functies te maken en die in aparte C-files te zetten.
* de globale variabelen die daarbijhoren, declareer je in dezelfde C-file. (int homeposition;)
* ALS een functie vanuit een ander file aangeroepen wordt, declareer je de functie in de bijbehorende header: extern somefunc (int a, float b);
* ALS een globale variabele van een module ook in een andere module gebruikt moet worden, dan declareer je die in de bijbehorende header: extern int homeposition;
* Als je een functie of variabele uit een andere module nodig hebt, dan zet je #include "module.h" boven aan je huidige C-file.

[Bericht gewijzigd door rew op 31 maart 2021 08:49:06 (28%)]

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Op 31 maart 2021 08:29:33 schreef rew:
* Bij het programmeren KAN je er altijd een zooitje van maken.

Inderdaad, en sommige programmeertalen lenen zich er beter voor om er een puinzooi van te maken terwijl er bij andere talen het meer moeite kost om er een zooitje van te maken.

Henri's Law 1: De wet van behoud van ellende. Law 2: Ellende komt nooit alleen.
trix

Golden Member

ik ga vrijdag of zaterdag kijken of ik de boel een beetje kan omzetten, dat met de .h en .c files gaat denk ik wel lukken. alleen zie ik wel op tegen de hoeveelheid variabelen die ik nodig heb.

als ik b.v. zoals hier is voorgesteld een .c file (source file heet dat geloof ik) gebruik voor een stepper motor. dan moet daar toch een flink aantal variabele naar heen en terug:
- homen en terug melden dat hij klaar is
- manual links en rechts
- positioneren met bijbehorende gewenste pos. waar hij naar toe moet.

dat is geen probleem ?
en wat ik mij ook afvroeg, als je elke stepper in een eigen source file doet, kunnen er dan nog steeds 2 stepper motoren tegelijk draaien (mocht ik dat willen) ?

eigenwijs = ook wijs

Ik weet niet hoe je de boel in gedachten had, maar ik zou denken dat je bijvoorbeeld om te homen iets doet als

code:


  rv = stepper_home (X_STEP_PIN, X_DIR_PIN, X_HOME_PIN);

En in stepper.c doe je dan:

code:


 
int stepper (int step, int dir, int sense)
{
  int to = 10000;

  digitalWrite (dir, 0);
  while (to--) {
     if (digitalRead (sense) == 1) return TRUE;
     digitalWrite (step, 1);
     delay_us (1);
     digitalWrite (step, 0);
     delay (HOME_DELAY_TIME); 
  }
  return FALSE; // home niet gelukt. 
}

Ik zie geen enkele reden om hiervoor globale variabelen nodig te hebben.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/