[C] Xcode linking error

Pagina: 1
Acties:

  • wacco
  • Registratie: Augustus 2002
  • Laatst online: 21-03-2023

wacco

cli, hlt.

Topicstarter
Hela,

Ik liep gisteravond tegen een probleem aan toen ik m'n code even wilde gaan opschonen en in twee aparte bestanden splitste. Nu weet ik daar tijdelijk omheen te werken (zie verder) maar bepaald fijn is het niet. Hopelijk weet iemand waar het probleem ligt want ik heb de afgelopen twee uur google afgespeurd en hopeloos weinig weten te vinden. Ik zit op m'n werk dus ik kan helaas niet de exacte meldingen geven die ld uitspuugt. Indien dit gewenst is zal het even tot vanavond moeten wachten.

Stel, ik heb drie bestanden;
C:
1
2
3
4
5
6
7
//main.c

#include "foo.h"

void main() {
  bar();
}


C:
1
2
3
4
5
6
7
8
9
10
11
//foo.h

#ifndef FOO
#define FOO

#include "stdio.h"
int blah = 123;

void bar();

#endif /* FOO */


C:
1
2
3
4
5
6
7
//foo.c

#include "foo.h" // Dank aan koli-man, ff vergeten in dit voorbeeld :P

void bar() {
  printf("%d\n", blah);
}


Als dit allen in een Xcode project staan gaat xcode dit vrolijk voor je compilen, maar doet dat per bestand. Hierdoor (dit is mijn interpretatie van het probleem iig) werkt de header guard niet meer, en wordt de variabele blah twee keer gedefinieerd. Namelijk, in main.o en foo.o. Wanneer ld dit dan vervolgens probeert te linken krijg ik een error iets in de trand van:

multiple definitions of blah, in main.o (data) & foo.o (data)

Door de #include lijn in main weg te halen wordt deze error opgelost, maar krijg je dus wel een waarschuwing. Namelijk:

implicit declaration of bar() in main.c

Nou ben ik daar dus ook niet heel erg blij mee, en hoop dat iemand weet wat dit veroorzaakt (is het wat ik denk dat het is) en hoe ik dit op kan lossen / omheen kan werken zonder waarschuwingen.

Wat google wel meldde leek erop dat het misschien met fink te maken had (dit is geinstalleerd en staat in de PATH), en voor de volledigheid; ik heb de openGL, GLUT en cocoa (nodig voor GLUT) frameworks in m'n project zitten. Ga er ook even vanuit dat blah niet weggeoptimaliseerd wordt in dit voorbeeld. ;)

Iemand dit eerder gezien? :/

[ Voor 9% gewijzigd door wacco op 22-09-2005 16:10 ]

Spolap: Interactive webcomic


  • koli-man
  • Registratie: Januari 2003
  • Laatst online: 01-04 11:43

koli-man

Bartender!!!!

Hoef jij in de foo.c file, de foo.h niet te includen?

Hey Isaac...let's go shuffleboard on the Lido - deck...my site koli-man => MOEHA on X-Box laaaiiiff


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 13:20

.oisyn

Moderator Devschuur®

Demotivational Speaker

de regel
C++:
1
int blah = 123;
is een definitie, geen declaratie. Je definieert nu dus een blah in elke sourcefile die je header include.

Een declaratie van een variabele doe je als volgt:
C++:
1
extern int bla;


En dan moet je 'm in een willekeurige sourcefile definieren (foo.c is in dit geval de beste keuze)

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.


  • wacco
  • Registratie: Augustus 2002
  • Laatst online: 21-03-2023

wacco

cli, hlt.

Topicstarter
Hmmkay, dus als ik blah geen waarde meegeef, en deze dan in bar_init() oid een iets toewijs dan werkt het wel?

Gaan we es proberen. Deed het al maar gaf het ook een beginwaarde mee (in case de init niet werd aangeroepen).

Spolap: Interactive webcomic


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 13:20

.oisyn

Moderator Devschuur®

Demotivational Speaker

Nee, niet geen waarde geven, je moet 'm als extern declareren. Daarmee zeg je tegen de compiler "er bestaat een int met de naam blah, maar waar die staat weet ik niet". Terwijl je met iets als int bla = 123; zegt: "Hier heb je een int variabele met de naam blah, en initialiseer 'm met 123"

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.


  • wacco
  • Registratie: Augustus 2002
  • Laatst online: 21-03-2023

wacco

cli, hlt.

Topicstarter
Uhm, nou ben ik in de war. :/

Hoe zit dat dan in foo.c? Daar alsnog declareren? Dat lijkt me nou niet bepaald netjes...
De variabele blah moet globaal beschikbaar zijn in foo.c, main.c heeft helemaal niks met deze var te maken en hoeft 'em ook niet aan te spreken.
Ik heb dit soort problemen nog nooit gehad, doe ik het al die tijd dan al fout? :X

Spolap: Interactive webcomic


  • BoAC
  • Registratie: Februari 2003
  • Laatst online: 06:41

BoAC

Memento mori

wacco schreef op donderdag 22 september 2005 @ 16:48:
Uhm, nou ben ik in de war. :/

Hoe zit dat dan in foo.c? Daar alsnog declareren? Dat lijkt me nou niet bepaald netjes...
Nee:
.oisyn schreef op donderdag 22 september 2005 @ 16:01:
de regel
C++:
1
int blah = 123;
is een definitie, geen declaratie. Je definieert nu dus een blah in elke sourcefile die je header include.

Een declaratie van een variabele doe je als volgt:
C++:
1
extern int bla;


En dan moet je 'm in een willekeurige sourcefile definieren (foo.c is in dit geval de beste keuze)
;)
[...]
Ik heb dit soort problemen nog nooit gehad, doe ik het al die tijd dan al fout? :X
Misschien? Geef es een voorbeeld? :)

  • wacco
  • Registratie: Augustus 2002
  • Laatst online: 21-03-2023

wacco

cli, hlt.

Topicstarter
Argh dat bedoelde ik dus. :)

Maar ik definieer m'n variabelen altijd in de headers, simpelweg na de structs. En toch is dit de eerste keer in al die tijd dat ik hier tegenaan loop. Vaag.
Daarentegen is dit de eerste keer dat ik mezelf met een tool probeer wijs te maken en niet m'n eigen makefiles in elkaar draai (waar ik al m'n sourcefiles in een keer compile, ipv apart en dan linken) dus misschien dat ik daarom dit probleem altijd heb 'ontweken'.

Verder, omdat die variabele alleen in foo.c beschikbaar hoort te zijn is de hele extern int in de header dus niet nodig. Right?

* wacco voelt zich een beetje van z'n c fundamentals afgeduwd.

Spolap: Interactive webcomic


  • BoAC
  • Registratie: Februari 2003
  • Laatst online: 06:41

BoAC

Memento mori

wacco schreef op donderdag 22 september 2005 @ 17:09:
Argh dat bedoelde ik dus. :)

Maar ik definieer m'n variabelen altijd in de headers, simpelweg na de structs. En toch is dit de eerste keer in al die tijd dat ik hier tegenaan loop. Vaag.
Daarentegen is dit de eerste keer dat ik mezelf met een tool probeer wijs te maken en niet m'n eigen makefiles in elkaar draai (waar ik al m'n sourcefiles in een keer compile, ipv apart en dan linken) dus misschien dat ik daarom dit probleem altijd heb 'ontweken'.
Als je een header-file maar 1 keer include gaat et goed ;)
Verder, omdat die variabele alleen in foo.c beschikbaar hoort te zijn is de hele extern int in de header dus niet nodig. Right?
Klopt ;)
* wacco voelt zich een beetje van z'n c fundamentals afgeduwd.
Why ;)

  • wacco
  • Registratie: Augustus 2002
  • Laatst online: 21-03-2023

wacco

cli, hlt.

Topicstarter
BoAC schreef op donderdag 22 september 2005 @ 17:11:
[...]
Als je een header-file maar 1 keer include gaat et goed ;)
Noop. Zoals ik het in de topic start geschreven had. Twee keer includen dus.

gcc -Wall main.c foo.c -o test of iets in die trant werkt zonder warnings of errors.

Spolap: Interactive webcomic


  • Coca-Cola
  • Registratie: Maart 2001
  • Laatst online: 14:14
wacco schreef op donderdag 22 september 2005 @ 17:19:
[...]


Noop. Zoals ik het in de topic start geschreven had. Twee keer includen dus.

gcc -Wall main.c foo.c -o test of iets in die trant werkt zonder warnings of errors.
Dat doet me aan iets denken... bestaat er onder linux niet al iets dat test heet? Ik compilede vroeger ook weleens progjes zo, maar als ik test dan wilde runnen werkte het niet ;)

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Declaratie in de header (extern int x), definitie in de source file (int x), simpel. Komt door de 'one definition rule', je mag geen twee dezelfde symbolen hebben met external linkage. Als je de variabele nou static zou maken, dan heeft hij internal linkage en kan het wel. Een nadeel is dan wel dat het twee verschillende variabelen worden, en veranderen ervan in de ene source file heeft dus geen effect op de variabele in de andere source file.

(dat is ook hoe je in C een soort van private/public specifiers in je modules kan maken. Een source file is als het ware een class, en private funties daarbinnen prefix je met 'static' zodat ze internal linkage krijgen en dus niet in een andere module zichtbaar zijn. Bij public functies doe je gewoon niets speciaals, zodat ze external linkage krijgen.

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// MyClass.h
#define public extern
#define private static

struct MyClass;
typedef struct MyClass MyClass;

public MyClass* new_MyClass();
public void foo(MyClass* self);

// MyClass.c
#include "myclass.h"

struct MyClass {
// data members
};

private void priv_call(MyClass* self) {
}

public MyClass* new_MyClass() {
   return 0; // actually malloc a new struct here, init it, and return a pointer to it
}

public void foo(MyClass* self) {
   priv_call(self);
}

// main.c
#include "myclass.h"

// can redefine here if you like, even with external linkage, it's a different function
void priv_call(MyClass* x) {
}

int main() {
    MyClass* x = new_MyClass();
    foo(x);
    return 0;
}


offtopic:
*shiver* ... C ... ook nog laten zien hoe je polymorphism/virtual functions kan maken in C? ;) Encapsulation...polymorphism...begint al bijna een OO taal te worden :P

[ Voor 69% gewijzigd door Zoijar op 22-09-2005 20:59 ]


  • wacco
  • Registratie: Augustus 2002
  • Laatst online: 21-03-2023

wacco

cli, hlt.

Topicstarter
Goed, wijziging even doorgevoerd en het werkt dus (zoals verwacht) maar ik heb nog steeds een naar gevoel over variabelen aan het begin van m'n c file. Nja, zal wel wennen worden dan. :P

offtopic:
Zoijar: ik hou je niet tegen, klinkt interessant ;)

Spolap: Interactive webcomic


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

wacco schreef op donderdag 22 september 2005 @ 23:28:
Goed, wijziging even doorgevoerd en het werkt dus (zoals verwacht) maar ik heb nog steeds een naar gevoel over variabelen aan het begin van m'n c file. Nja, zal wel wennen worden dan. :P

offtopic:
Zoijar: ik hou je niet tegen, klinkt interessant ;)
Het is een beetje flauw, en ziet er ingewikkeld uit, maar je kan het nog versimpelen. Helemaal als je wat macro's gaat definieren, dan is er best een bruikbaar systeem van te maken.

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <stdio.h>
#include <stdlib.h>

/* Class Methods */
void Base_foo() {
    printf("Base::foo\n");
}
void Base_blah() {
    printf("Base::blah\n");
}

void Derived_foo() {
    printf("Derived::foo\n");
}
void Derived_bar() {
    printf("Derived::bar\n");
}

/* Internal, private structures */
struct vt_Base{
    void (*foo)();
    void (*blah)();
} vt_Base;

struct vt_Derived {
    void (*foo)();
    void (*blah)();
    void (*bar)();
} vt_Derived;

/* Class data */
typedef struct Base {
    struct vt_Base* vtbl;
    int x;
} Base;


typedef struct Derived {
    struct vt_Derived* vtbl;
    int x;
    int y;
} Derived;

/* Constructors */
Base* new_Base() {
    Base* b = (Base*)malloc(sizeof(Base));
    b->vtbl = &vt_Base;
    return b;
}

Derived* new_Derived() {
    Derived* d = (Derived*)malloc(sizeof(Derived));
    d->vtbl = &vt_Derived;
    return d;
}

/* Initialization of vtables */
void init() {
    vt_Base.foo = &Base_foo;
    vt_Base.blah = &Base_blah;

    vt_Derived.foo = &Derived_foo;  /* virtual, overload */
    vt_Derived.blah = &Base_blah;   /* virtual, non-overload */
    vt_Derived.bar = &Derived_bar;  /* plain */
}

/* Main program */

void print(Base* base) {
    base->vtbl->foo();  
}


int main() {
    init();

    Base* b1 = new_Base();
    Derived* d = new_Derived();
    Base* b2 = (Base*)d;

    print(b1);
    print(b2);
    
    b1->vtbl->foo();
    b2->vtbl->foo();
    
    b1->vtbl->blah();
    b2->vtbl->blah();
    
    d->vtbl->bar();     
    
    return 0;
}

  • BoAC
  • Registratie: Februari 2003
  • Laatst online: 06:41

BoAC

Memento mori

Zoijar schreef op vrijdag 23 september 2005 @ 11:06:
[...]

Het is een beetje flauw, en ziet er ingewikkeld uit, maar je kan het nog versimpelen. Helemaal als je wat macro's gaat definieren, dan is er best een bruikbaar systeem van te maken.

C:
1
[...Veel Code ...];
Grappig hoef je niet meer te linken tegen die C++ libs van gnu en kun je toch gebruik maken van OO :D

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Is het nu C of C++? C heeft iets ingewikkelds als tentative definitions;
C:
1
2
int c;
int c; 
is niet fout.
C++:
1
2
int c;
int c; 
wel.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 13:20

.oisyn

Moderator Devschuur®

Demotivational Speaker

MSalters: wat is het gedrag in C in zo'n geval? Is het dezelfde variabele, of hide de laatste definitie de eerste? En als het dezelfde variabele is: wat gebeurt er dan als je ze beide initialiseert met verschillende waardes?

[ Voor 8% gewijzigd door .oisyn op 23-09-2005 13:25 ]

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