[C] #ifndef & waarvoor is extern

Pagina: 1
Acties:

  • Gehakt
  • Registratie: Juli 2002
  • Laatst online: 24-10 20:19
Ik ben bezig met een programma voor een arm target. Op dit moment heb ik mijn code zo opgedeeld in files.

file1.c & file1.h + file2.c & file2.h etc & main.c + main.h met in main.h alle andere fileX.h geinclude.
Nou is mijn eerste vraag of dat dat een beetje gangbare opzet is.

Verder lees ik op verschillende plaatsen dat het handig is om in include files het volgende te gebruiken:
C:
1
2
3
4
5
6
#ifndef _FILE_NAME_H_
#define _FILE_NAME_H_

/* code */

#endif // #ifndef _FILE_NAME_H_
Dit om te voorkomen dat files meerdere keren geinclude worden wat naar ik begrijp problemen kan geven bij het compileren. Het is voor mij alleen nog een beetje onduidelijk of dit alleen bij C++ gebruikt wordt of ook voor C?

Verder vroeg ik mij af waarom in sommige gevallen ook nog het volgende word gedaan:
C:
1
2
3
4
5
6
7
#ifndef _FILE_NAME_H_
#define _FILE_NAME_H_

int functie();
#else
extern int functie();
#endif // #ifndef _FILE_NAME_H_
Waarvoor is het extern gedeelte precies?

[ Voor 0% gewijzigd door Gehakt op 20-11-2006 12:59 . Reden: een #endif teveel weggehaald ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 18:04
Over welke taal heb je het nu ?
In je topic - titel staat C#, maar C# werkt niet met *.h files en *.c files, maar met *.cs files.

Volgens mij werk je dus in C++ ?

https://fgheysels.github.io/


  • Gehakt
  • Registratie: Juli 2002
  • Laatst online: 24-10 20:19
in de topic titel staat [C] #ifndef. Ik werk in C

  • .oisyn
  • Registratie: September 2000
  • Nu online

.oisyn

Moderator Devschuur®

Demotivational Speaker

whoami: In de topictitel staat niet C# maar C ;)

Die header guards zijn uiteraard voor zowel C++ als C, je wil namelijk in beide niet dat dingen dubbel geinclude worden.
Waarom sommigen die extern gebruiken bij functies afhankelijk van een bepaalde #if (je code klopt trouwens niet, er staat 1 #ifndef maar 2 #endifs) is me onduidelijk, in principe hoef je voor functies sowieso nooit extern te gebruiken. Voor variabelen natuurlijk wel, maar zet die dan gewoon als extern in de header en zonder extern in de bijbehorende sourcefile

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • MTWZZ
  • Registratie: Mei 2000
  • Laatst online: 13-08-2021

MTWZZ

One life, live it!

Dit wordt ook gewoon voor C gedaan hoor, zoals .oisyn al zegt.
Wat je vaker ziet met die else constructie is dat er dmv autoconfig/automake een config.h gemaakt wordt waarin een aantal zaken ge#defined worden om zo te kunnen bepalen of een bepaalde functie wel of niet beschikbaar is op een target systeem.

offtopic:
damn you .oisyn :( :P

[ Voor 79% gewijzigd door MTWZZ op 20-11-2006 12:45 ]

Nu met Land Rover Series 3 en Defender 90


  • Gehakt
  • Registratie: Juli 2002
  • Laatst online: 24-10 20:19
aha...vrij duidelijk antwoord. :p

  • whoami
  • Registratie: December 2000
  • Laatst online: 18:04
eh, ok, te snel gelezen. :+

https://fgheysels.github.io/


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 30-11 00:17
.oisyn schreef op maandag 20 november 2006 @ 12:43:
....in principe hoef je voor functies sowieso nooit extern te gebruiken...
extern

Indicates that an identifier is defined elsewhere.

Keyword extern indicates that the actual storage and initial value of a variable, or body of a function, is defined elsewhere, usually in a separate source code module. So, it may be applied to data definitions and function prototypes:

extern data-definition;
extern function-prototype;

For example,

extern int _fmode;
extern void Factorial (int n);

The keyword extern is optional (i.e. default) for a function prototype.
Maw een functie is altijd extern ook al zet je het er niet bij.

[ Voor 4% gewijzigd door farlane op 20-11-2006 16:48 ]

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Verwijderd

Of het een goede constructie is om alle .h files te includen in je main.h is afhankelijk van de situatie; meestal include je pas een .h file als je iets nodig hebt uit die desbetreffende file; dus meestal in je .c file. Beste constructie, naar mijn mening dan, is om zo min mogelijk includes te hebben in je .h files, includen in de .c file waar die ook echt nodig is, is volgens mij de beste optie.

  • .oisyn
  • Registratie: September 2000
  • Nu online

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op maandag 20 november 2006 @ 17:45:
Beste constructie, naar mijn mening dan, is om zo min mogelijk includes te hebben in je .h files, includen in de .c file waar die ook echt nodig is, is volgens mij de beste optie.
Ja en nee. Idd zo min mogelijk includen, maar wel die dingen die nodig zijn voor die header. Je wil namelijk niet dat iemand compile errors krijgt omdat ie henk.h include zonder eerst bert.h te includen. Als henk.h definities nodig heeft uit bert.h, dan moet henk.h zelf ook bert.h includen.

En dan heb je nog het verschil tussen definitie en declaratie. Als je alleen een declaratie nodig hebt ("er bestaat een ...", zoals een extern variabele, een functie, of een class/struct declaratie in de vorm "class x;") zoals bij pointers, references en function arguments en return types het geval is, dan voeg je zelf gewoon die declaratie toe in de header. Als henk.h dus een functie declareert die een pointer naar Bert als argument heeft, dan ziet henk.h er zo uit:
C++:
1
2
3
class Bert;

void HenksFuncie(Bert * b);


Voor definities ("Hier is een ...", voor volledige class/struct/enum definities en typedefs) moet je wel de relevante header includen. Dus als henk.h een class definieert die een Bert als member heeft, dan moet ie dus ook bert.h includen:
C++:
1
2
3
4
5
6
#include "bert.h"

class Henk
{
    Bert bert;
};

[ Voor 5% gewijzigd door .oisyn op 20-11-2006 18:01 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 30-11 00:17
Ik heb dat idd vaker gezien, maar is dat niet ontzettend onhandig als die functie plotseling een Karel* parameter erbij krijgt? Dan moet je alle sources langs waar HenksFunctie wordt gebruikt om die Karel ook als declaratie toe te voegen.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • Gehakt
  • Registratie: Juli 2002
  • Laatst online: 24-10 20:19
Om het dan toch ook maar even te vragen.
In mijn geval programmeer ik voor een arm bordje waar ook onder andere een gsm & gps module op zit.

(Er is overigens niemand in het bedrijf die echt verstand heeft van programmeren dus ik moet het allemaal zelf uitzoeken en vraag me soms af of ik het wel goed doe :P, wil geen slechte gewoonten aanleren.)

Op het armbordje staat een kale linux versie met wat voorgecompileerde libraries. Hier zitten de functies in om het geheel te initialiseren, gps & gms aan te sturen, etc.

Ik programmeer nu op deze manier.

main.c (hoofdprogramma) - include main.h, en zo nodig loadgsm.h, loadgps.h etc voor elke module.
main.h
loadgsm.c - include loadgsm.h (in .c staan de daadwerkelijke functies om de dynamische libraries te laden met dylsm)
loadgsm.h - hierin staan alle prototypes voor de functies in loadgsm.c

ophet moment dat ik dus bijvoorbeeld de gsm module wil gebruiken hoef ik alleen loadgsm.h te includen in main.c en ik kan de functies gebruiken.

Hierdoor lijkt het me dat deze code opzet voor elk project te gebruiken is en ik desgewenst modules kan laden of weglaten.

Het probleem is dat we op school, electrotechniek wel wat C krijgen maar eigenlijk helemaal niets wat de opzet van programmacode behandeld oid (richting embedded systems). Voor ik met mijnstage begon wist ik uberhaupt nog niet hoe ik voorgecomileerde libraires moest gebruiken.

Misschien is mijn verhaaltje een beetje moeilijk te begrijpen trouwens. :+

  • .oisyn
  • Registratie: September 2000
  • Nu online

.oisyn

Moderator Devschuur®

Demotivational Speaker

farlane schreef op maandag 20 november 2006 @ 22:48:
Ik heb dat idd vaker gezien, maar is dat niet ontzettend onhandig als die functie plotseling een Karel* parameter erbij krijgt? Dan moet je alle sources langs waar HenksFunctie wordt gebruikt om die Karel ook als declaratie toe te voegen.
:?
De declaratie voeg je aan de header toe, anders compileert die functiedeclaratie niet eens. En degene die HenksFunctie gebruiken en daarvoor een Karel moeten bewerken, moeten dan idd Karel.h gaan includen. Maar dat is niet zo raar, je gebruikt immers nieuwe types in die sourcefiles. Het is niet zo dat je ineens sources die die header includen maar niets met die functie doen aan moet gaan passen.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 30-11 00:17
.oisyn schreef op maandag 20 november 2006 @ 23:42:
De declaratie voeg je aan de header toe, anders compileert die functiedeclaratie niet eens. En degene die HenksFunctie gebruiken en daarvoor een Karel moeten bewerken, moeten dan idd Karel.h gaan includen. Maar dat is niet zo raar, je gebruikt immers nieuwe types in die sourcefiles. Het is niet zo dat je ineens sources die die header includen maar niets met die functie doen aan moet gaan passen.
Ah nee, ik was niet aan het opletten :O. Die fwd decl heb je in de header van Henk staan dus dan hoef je Karel ook alleen daar toe te voegen.

Ikzelf heb altijd de neiging om Bert.h en Karel.h te includen vanuit Henk.h om de reden die je zelf ook al aangaf.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 30-11 00:17
Gehakt schreef op maandag 20 november 2006 @ 23:34:
Het probleem is dat we op school, electrotechniek wel wat C krijgen maar eigenlijk helemaal niets wat de opzet van programmacode behandeld oid (richting embedded systems). Voor ik met mijnstage begon wist ik uberhaupt nog niet hoe ik voorgecomileerde libraires moest gebruiken.
Structuur van code is niet anders als je embedded gaat programmeren. :)

Als je aanhoudt dat je in je header alleen de functies exporteert die je vanuit andere modules wilt gebruiken, en het liefst zo min mogelijk andere headers include krijg je ook zo min mogelijk dependencies.
Veel dependencies is een indicatie dat de structuur van je code niet optimaal is, je weet wel loose coupling ( http://en.wikipedia.org/wiki/Coupling_%28computer_science%29 ) , high cohesion ( http://en.wikipedia.org/wiki/Cohesive ) enzo. ( is eigenlijk een OO ding maar geldt imho ook net zo goed voor dit soort dingen )

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • .oisyn
  • Registratie: September 2000
  • Nu online

.oisyn

Moderator Devschuur®

Demotivational Speaker

farlane schreef op dinsdag 21 november 2006 @ 00:55:
Ikzelf heb altijd de neiging om Bert.h en Karel.h te includen vanuit Henk.h om de reden die je zelf ook al aangaf.
Met als resultaat dat je extra dependencies introduceert die compiletijden om 2 redenen doen toenemen: er moet meer code geparsed worden, en meer files moeten opnieuw gecompileerd worden zodra je een van headers aanpast.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 30-11 00:17
.oisyn schreef op dinsdag 21 november 2006 @ 02:20:
[...]

Met als resultaat dat je extra dependencies introduceert die compiletijden om 2 redenen doen toenemen: er moet meer code geparsed worden, en meer files moeten opnieuw gecompileerd worden zodra je een van headers aanpast.
Ja dat klopt. Aan de andere kant als mijn module een header importeert waarin een Karel* wordt gebruikt dan zou hij daar een goede reden voor moeten hebben.
Als het echt een unrelated ding zou zijn zou die eigenlijk in een derde header moeten staan die alleen vanuit Henk.c wordt geinclude, en zou de functie niet in Henk.h worden geexporteerd.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • .oisyn
  • Registratie: September 2000
  • Nu online

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ik vind het wat kortzichtig om te stellen dat je in de gevallen dat je HenksFunctie aanroept ook altijd per se moet weten hoe een Karel in elkaar zit. En als HenksFunctie Henk::Functie had geheten dan had je 'm niet eens in een andere header kunnen zetten, maar zit je toch Karel.h te includen zonder dat je vanuit bepaalde sourcefiles Henk::Functie ooit aan gaat roepen.

Ik weet niet hoe het bij jullie zit maar een volledige rebuild van een project hier kost pakweg een uur. Als je dan een cruciale header aanpast die iedereen include zonder dat mensen 'm eigenlijk nodig hebben omdat ze jouw filosofie aangehouden hebben zit je al gauw de helft van die tijd te wachten. Daar wordt ik persoonlijk niet zo heel erg vrolijk van :)

[ Voor 32% gewijzigd door .oisyn op 21-11-2006 11:07 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 30-11 00:17
.oisyn schreef op dinsdag 21 november 2006 @ 11:03:
Ik vind het wat kortzichtig om te stellen dat je in de gevallen dat je HenksFunctie aanroept ook altijd per se moet weten hoe een Karel in elkaar zit.
Dat zal ongetwijfeld niet in alle gevallen zo zijn. Kan me echter zo snel niet voor de geest halen of ik dit ooit ben tegengekomen. ( Vast wel :) )
En als HenksFunctie Henk::Functie had geheten dan had je 'm niet eens in een andere header kunnen zetten, maar zit je toch Karel.h te includen zonder dat je vanuit bepaalde sourcefiles Henk::Functie ooit aan gaat roepen.
Klopt. Maar ik heb het gevoel dat die situaties op te lossen zijn door bv een helper class te introduceren.
Ik weet niet hoe het bij jullie zit maar een volledige rebuild van een project hier kost pakweg een uur. Als je dan een cruciale header aanpast die iedereen include zonder dat mensen 'm eigenlijk nodig hebben omdat ze jouw filosofie aangehouden hebben zit je al gauw de helft van die tijd te wachten. Daar wordt ik persoonlijk niet zo heel erg vrolijk van :)
Kan ik me voorstellen. :) Iha zijn de projecten waaraan ik werk niet van die omvang dus ik heb er niet zoveel ervaring mee.

Volgens mij staat er in het boek van Stroustrup een hoofdstuk over hoe je de structuur van je modules zou moeten aanhouden om zoveel mogelijk dependencies te elimineren ( en dus compile tijden ). Ga ik toch nog maar eens doorlezen want ook al zijn de gevolgen voor mijn projecten niet zo groot een goede structuur is natuurlijk een must voor elk project, ongeacht de grootte. :)

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • .oisyn
  • Registratie: September 2000
  • Nu online

.oisyn

Moderator Devschuur®

Demotivational Speaker

farlane schreef op dinsdag 21 november 2006 @ 14:00:
Klopt. Maar ik heb het gevoel dat die situaties op te lossen zijn door bv een helper class te introduceren.
C++: Henk.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef HENK_H
#define HENK_H

class Karel;

class Henk
{
public:
    void DoeIetsBelangrijks();

    void SetKarel(Karel * m_pKarel);
    Karel * GetKarel() const { return m_pKarel; }

private:
    Karel * m_pKarel;
};

#endif // HENK_H


C++: Piet.cpp
1
2
3
4
5
6
7
#include "Henk.h"

void PietsFunctie()
{
    Henk henk;
    henk.DoeIetsBelangrijks();
}


C++: Dirk.cpp
1
2
3
4
5
6
7
8
9
10
#include "Henk.h"
#include "Karel.h"

void DirksFunctie()
{
    Henk henk;
    Karel karel;
    henk.SetKarel(&karel);
    henk.DoeIetsBelangrijks();
}

[ Voor 3% gewijzigd door .oisyn op 21-11-2006 14:08 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1