Avatar billede susrn Nybegynder
10. marts 2003 - 10:09 Der er 23 kommentarer og
3 løsninger

variable i header eller cpp (borland c++ builder)

Hvad er forskellen på om jeg erklærer en variabel i header fil som private eller i cpp fil (udenfor metode/function)?

Og hvilken forskel gør det om man erklærer #include xxx i header eller cpp?
Avatar billede hsloth Novice
10. marts 2003 - 10:35 #1
Når man erklærer noget i en header fil vil det typisk blive inkluderet af flere cpp filer. Det betyder at hvis man erklærer en variabel i en include fil med :

// x.h
int Xint;

og derefter inkluderer x.h i to filer (a.cpp og b.cpp) vil Xint findes i både a.obj og b.obj når man har kompileret. Når man senere linker sit program vil linkeren klage over at Xint er defineret to gange.

Ved at erklære Xint i den ene af .cpp filerne sikrer man sig at den blive oprettet netop en gang.
Avatar billede olennert Nybegynder
10. marts 2003 - 10:36 #2
Forskellen er om variablen er tilgængelig per instans af din klasse, eller som en enkelt global instans. Når du har en medlemsvariabel (private, protected eller public), så har du en variabel per instans. Når den samme variabel er global i din .cpp fil, så har du kun en af dem, uanset hvor mange instanser du har gang i. Det giver øget kompleksitet i et flertrådet miljø.

Forskellen mellem #include xxx i din header eller .cpp fil er at når du har #include xxx i din .h fil, så bliver indholdet af xxx kopieret ind i din .h fil. Når du har #include xxx i din .cpp fil, så bliver indholdet af xxx kopieret ind i din .cpp fil.

Generelt bør du lave dine .h filer stand-alone. Det vil sige, hvis du vil bruge funktionalitet du har defineret i en .h fil bør det kun være nødvendigt at #include den ene .h fil. Så hvis du bruger std::string i din .h fil, så skal du lave #include <string> i din .h fil.
Avatar billede hsloth Novice
10. marts 2003 - 10:45 #3
Ved at lade en include file inkluderer andre include filer kan man lette brugen af include filen. F.eks.

//x.h
#include "y.h"

class x
{
  Y myY;
}

Når man skal bruge x klassen behøver man kun inkludere x.h. Hvis man udelader at inkluderer y.h i x.h skal dem der bruger x.h selv huske at inkludere y.h - kompileren vil dog opmærksom på at der mangler noget.

Ulempen ved at lade inklude filer inkludere andre filer er at det kan være svært at overskue hvilken rækkefølge tingene kommer ind i. I projekter med mange source filer kan man også risikere at man får hentet den samme fil ind rigtigt mange gange, fordi man har header filer der inkluderer hinanden.
Avatar billede olennert Nybegynder
10. marts 2003 - 11:25 #4
hsloth>
Og derfor er det en *rigtig* god ide med include guards i .h filer:

#ifndef MY_HEADER_FILE_H_
#define MY_HEADER_FILE_H_

// Og her er så erklæringer med mere

#endif

Så får du godt nok hentet det ind flere gange (idet præprocessoren er ganske uintelligent), men det bliver kun erklæret en gang, og belaster oversætteren minimalt.
Avatar billede hsloth Novice
10. marts 2003 - 11:34 #5
Du skal lige være opmærksom på at olennert og mit svar er forskellige da vi har taget forskellige udgangspunkter - olennert antager at du erklærer din variabel inden i en klasse (class-scope) og jeg antager at du har erklæret den udenfor (fil-scope)
Avatar billede olennert Nybegynder
10. marts 2003 - 11:56 #6
Ja; C++ er bare dejligt komplekst :-)
Avatar billede arne_v Ekspert
10. marts 2003 - 16:03 #7
Med al respekt så synes jeg altså at der mangler et
par betragtninger omkring erklæringen af variable udenfor
klasser/metoder.

Løsningen på multiple definition er ikke at flytte fra .H til .C/.CPP.

Hvis den kun skal bruges i en enkelt .C/.CPP så erklærer man den
i .C/.CPP med static altså:
  static int Xint;
så er der ingen konflikter.

Hvis den skal bruges i flere .C/.CPP så skal den erklæres
  int Xint;
1 sted og:
  extern int Xint;
alle de andre steder.

Der er forskellige måder at gøre det på. En er at erklære den med
extern i en .H og den uden extern i en enkelt .C/.CPP som ikke
inkluderer den .H. En anden er at erklære som følger:
  EXTERN int Xint;
og så have
  #define EXTERN extern
for alle .C/.CPP undtagen en som har:
  #define EXTERN

Jeg vil tillade mig at konkludere at C++ har kønnere måder at gøre det
på end C.
Avatar billede olennert Nybegynder
10. marts 2003 - 16:11 #8
arne, hvorfor erklærer du Xint static i det første eksempel? Hvis det er for at undgå at symbolet bliver eksporteret, så vil jeg foretrække anonymt namespace.
Avatar billede arne_v Ekspert
10. marts 2003 - 16:18 #9
Fordi det virker i C.

Og i C++ ville jeg forsøge at undgå den slags variable totalt.
Og bruge singleton pattern, static class member eller sådan.
Avatar billede olennert Nybegynder
10. marts 2003 - 16:34 #10
Ah, tak. Så forstår jeg bedre. Jeg burde have læst dit svar lidt mere grundigt, så var det nok gået op for mig at du skrev om både C og C++.
Avatar billede arne_v Ekspert
10. marts 2003 - 16:41 #11
Det oprindelige spørgsmål gik jo også på C++.

Men diskussionen udvikling gjorde det efter min mening relevant
at komme lidt ind på C.
Avatar billede hsloth Novice
10. marts 2003 - 18:21 #12
arne_v>
Normalt er der ingen problemer i at compilere :
int Xint;
extern Xint;

og så der er ingen grund til at lave nogen #define EXTERN krumspring.
Avatar billede arne_v Ekspert
10. marts 2003 - 19:02 #13
hsloth>

????

Det kode vil efter min bedste overbevisning give syntax fejl.

Men hvis vi nu formoder at du mener:

extern int Xint;

i .H.

og:

int Xint i en .C/.CPP som inkluderer .H efter den erklæring.

Den lider jo af samme problem som løsningen med include undtagen
i en .C/.CPP.

Man har en afhængighed mellem 2 source-filer som ikke kan checkes
af compileren.
Avatar billede arne_v Ekspert
10. marts 2003 - 19:03 #14
#define tricket gør at selve erklæringen kun er i 1 source fil.
Avatar billede susrn Nybegynder
10. marts 2003 - 20:32 #15
mange tak allesammen!
Avatar billede hsloth Novice
10. marts 2003 - 21:54 #16
arne_v>
Nu er du jo ikke en compiler, så check hvad der sker hvis du compiler en fil der indeholder :

extern int X;
int X;

eller

int X;
extern int X;

Sålænge de to erklæringer definerer X som den samme type er alt i den skønneste orden. Det er klart at hvis man laver en direkte og en extern erklæring hvor typerne ikke er de samme så vil kompileren give en fejl.

extern int X opretter et entry i symbol tabellen, med mindre der er et i forvejen.

int X erklæringen opretter et entry i symbol tabellen (med mindre der er et i forvejen) _og_ sørger for at der når den færdige eksekverbare bliver loadet bliver afsat plads til en integer.

Du skriver : "Den lider jo af samme problem som løsningen med include undtagen
i en .C/.CPP." - det forstår jeg ikke ?


Jeg kan ikke se hvad der er for en afhængighed der ikke kan checkes af kompileren.
Avatar billede arne_v Ekspert
10. marts 2003 - 22:30 #17
C:\>type z.cpp
int Xint;
extern Xint;

int main()
{
}

C:\>g++ z.cpp -o z.exe
z.cpp:2: ISO C++ forbids declaration of `Xint' with no type
Avatar billede arne_v Ekspert
10. marts 2003 - 22:33 #18
Du manglede en int i din post.
Avatar billede hsloth Novice
10. marts 2003 - 22:35 #19
arne_v>
Du mangler en type.

extern int Xint;
ikke
extern Xint;

brug copy og paste - og læs evt. fejlmeddelelsen fra compileren inden du poster næste gang
Avatar billede arne_v Ekspert
10. marts 2003 - 22:37 #20
Og problemet jeg snakker om er, at du får 2 linier i 2 forskellige filer
som skal have samme type og samme navn. Ellers så vil applikationen
ikke virke korrekt. Og compileren vil ikke altid kunne fange det.

Hvis man bruger #define så står navn og type kun 1 gang i 1 fil.
Avatar billede arne_v Ekspert
10. marts 2003 - 22:39 #21
hsloth>

Læs dit eget indlæg 18:21:35 !!!!
Avatar billede hsloth Novice
10. marts 2003 - 22:41 #22
arne_v>
Min kommentar gik på din udtalelse :

"En er at erklære den med extern i en .H og den uden extern i en enkelt .C/.CPP som ikke inkluderer den .H. "

Det jeg ikke forstår er hvorfor du vil have den direkte erklæring (uden extern) í en .c/.cpp fil der ikke inkludere den .h fil der hvori extern erklæringen findes.
Avatar billede hsloth Novice
10. marts 2003 - 22:44 #23
arne_v> (22:37:25)
"Og compileren vil ikke altid kunne fange det" - Kunne du lokkes til at give et eksempel
Avatar billede arne_v Ekspert
10. marts 2003 - 22:44 #24
Det var såmænd fordi jeg ikke var klar over at det var legalt at
have begge i samme fil.

Men som jeg har forsøgt at forklare så gør det ikke den store
forskel.
Avatar billede arne_v Ekspert
10. marts 2003 - 23:32 #25
MIMER::ARNE> typ ext.h
extern int n;

void f();

MIMER::ARNE> typ ext1.c
#include "ext.h"

int newn; // omdøbt fra n til newn

int main()
{
  newn = 2;
  f();
}

MIMER::ARNE> typ ext2.c
#include <stdio.h>

#include "ext.h"

void f()
{
    printf("n=%d\n",n);
}

Compileren giver ingen fejl på den her.

Linkeren giver måske fejl, fordi n ikke er defineret nogen
steder.

Men det kan man ikke regne med.

MIMER::ARNE> cc/standard=ansi ext1
MIMER::ARNE> cc/standard=ansi ext2
MIMER::ARNE> link ext1+ext2
%LINK-W-NUDFSYMS, 1 undefined symbol:
%LINK-I-UDFSYM,        N
%LINK-W-USEUNDEF, undefined symbol N referenced
        in psect $LINK$ offset %X00000020
        in module EXT2 file SYS$SYSDEVICE:[USER.ARNE]EXT2.OBJ;5

MIMER::ARNE> cc/standard=ansi/extern=common ext1
MIMER::ARNE> cc/standard=ansi/extern=common ext2
MIMER::ARNE> link ext1+ext2
MIMER::ARNE> r ext1
n=0

ANSI C definerer ikke hvordan linkere skal håndtere den
situation.

Undefined behaviour.
Avatar billede arne_v Ekspert
10. marts 2003 - 23:33 #26
Ovenstående compiler har 2 måder at håndtere externe
symboler på. Den ene giver linker fejl - den anden gør
ikke.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester