[ Texas Instruments @ 27.03.2012. 11:15 ] @
Kako da definišem strukturu u nekom .h fajlu, koji će biti uključen u više .c fajlova, a da izbegnem grešku prilikom linkovanja o višestrukom definisanju?

Npr. heder fajl bi izgledao ovako.

Code:

#ifndef HEDER_H_
#define HEDER_H_

struct X {
    int a;
    int b;
};

struct X nizX [] = {
        [0] = {
                .a = 1,
                .b = 2,
        },
        [1] = {
                .a = 3,
                .b = 4,
        },
        [2] = {
                .a = 5,
                .b = 6,
        },
};

#endif /* HEDER_H_ */


A onda u nekim drugim .c fajlovima da imam #include "heder.h". Imam problem sa nekim kodom koji nisam ja pisao, a treba da ga nekako lokalizujem, tako da se na što manje mesta vrši izmena u programu. Ova strukutra se definiše prilikom menjanja programa i još neke stvari pa sam to mislio da izvučem u poseban fajl.
[ deerbeer @ 27.03.2012. 11:32 ] @
Upravo ovaj
Citat:

#ifndef HEDER_H_
#define HEDER_H_
..
..
..
#endif

bi trebalo da ti sredi problem visestrukog definisanje strukture ...
[ Texas Instruments @ 27.03.2012. 11:39 ] @
To sam i ja mislio, ali nije. Evo npr. kako izgledaju ti .c fajlovi.

Code:

// prvi.c

#include "heder.h"

void t(int a, int b) {
    nizX[0].a = a;
    nizX[0].b = b;
}


Code:

// drugi.c

#include "heder.h"
#include <stdio.h>

int main() {
    nizX[1].a = 5;
    nizX[2].b = 6;

    int i;
    for (i = 0; i < sizeof(nizX)/sizeof(struct X); i++) {
        printf("%d := %d %d", i, nizX[i].a, nizX[i].b);
    }
    return 0;
}


Linker prijavljuje grešku.
[ deerbeer @ 27.03.2012. 12:14 ] @
Hmm... probaj sa
Code:
 
#pragma once 


umesto onog ifndef-a

mada je to u principu isto ..
Prikazi celu gresku koju ti linker izbacuje ..

Da li externi lib ima neke linkovane module ili tako nesto ..
Vrlo moguce je da mozda nisi setovao neki #define za taj lib pa prilikom kompajliranja odlazi u drugu granu definicije gde ne bi trebalo pa je to uzrok greske ...




[ Texas Instruments @ 27.03.2012. 13:41 ] @
Evo bukvalno ovako sam napravio fajlove kao test primer i isto mi se dešava.

Code:

// heder.h

#ifndef HEDER_H_
#define HEDER_H_

struct X {
    int a;
    int b;
};

struct X nizX[] = {
        [0] = {
                .a = 1,
                .b = 2,
        },
        [1] = {
                .a = 3,
                .b = 4,
        },
        [2] = {
                .a = 5,
                .b = 6,
        },
};

#endif /* HEDER_H_ */


Code:

// prvi.c

#include "heder.h"

void t(int a, int b) {
    nizX[0].a = a;
    nizX[0].b = b;
}


Code:

// drugi.c


#include "heder.h"
#include <stdio.h>

int main() {
    nizX[1].a = 5;
    nizX[2].b = 6;

    int i;
    for (i = 0; i < sizeof(nizX)/sizeof(struct X); i++) {
        printf("%d := %d %d", i, nizX[i].a, nizX[i].b);
    }
    return 0;
}


Eclipse C projekat sa mingw kompajelrom.

Code:
Description                           Resource    Path                 Location    Type
first defined here                      prvi.c    /struktura/src            C/C++ Problem
multiple definition of `nizX'     drugi.c    /struktura/src            C/C++ Problem


Code:

**** Build of configuration Debug for project struktura ****

**** Internal Builder is used for build               ****
gcc -O0 -g3 -Wall -c -fmessage-length=0 -o src\drugi.o ..\src\drugi.c
gcc -o struktura.exe src\prvi.o src\drugi.o
src\drugi.o:drugi.c:(.data+0x0): multiple definition of `nizX'
src\prvi.o:prvi.c:(.data+0x0): first defined here
collect2: ld returned 1 exit status
Build error occurred, build is stopped
Time consumed: 438  ms.  


Verovatno treba negde da se stavi extern, ali ni to nisam uspeo da provalim.
[ milanche @ 27.03.2012. 19:19 ] @
Instancijacija strukture globalnog scope-a/vidljivosti treba da se obavi na samo jednom mestu,
a to ne moze da bude header fajl koji se include-uje na vise mesta.

Bolje je da se obavi u nekom od source fajlova u projektu. Definicija structX treba da ostane u
heder.h, i source fajl u kojem se instancira nizX treba da include-uje heder.h. U svim ostalim
source fajlovima koji referenciraju nizX treba da se include-uje heder.h kao i da se deklarise
eksterni simbol:

Code:

extern struct X nizX;


negde na pocetku svakog od fajlova. Ovako definisano, linker nece imati problema da bez zabune,
jednoznacno razresi (resolve) simbol.


[Ovu poruku je menjao milanche dana 27.03.2012. u 21:58 GMT+1]
[ Texas Instruments @ 27.03.2012. 19:44 ] @
Pretpostavio sam da je tako nešto u pitanju. Problem je što sam hteo da sve takve strukture koje se definišu u zavisnosti od nekih parametara izdvojim u poseban fajl kako ne bi morao da menjam na "sto" mesta u kodu, pa mi je logično bilo da napravim poseban .h fajl u kojem bi to definisao i onda uključivao gde mi je potrebno.
[ milanche @ 27.03.2012. 21:02 ] @
Ni to nije problem.

Rezervisi jedan source fajl (.cpp) da sadrzi instance struktura konstantog (preset) sadrzaja.
Te instance mozes da stavis u niz (array) kao sto si vec krenuo (structX nizX[]).

Sve ostalo ide na isti recept - kome god taj niz treba, deklarise ga kao extern, i menja samo
indeks kojim prema potrebi pristupa clanicama.
[ Texas Instruments @ 28.03.2012. 10:52 ] @
Ali imam sledeći problem. Kada uključim .h fajl i deklarišem niz struktura sa extern, prilikom prolaska kroz petlju
Code:

for (i = 0; i < sizeof(nizX)/sizeof(struct X); i++) {
        printf("%d %d\n", nizX[i].a, nizX[i].b);
    }

dobijam grešku.
Code:

invalid application of 'sizeof' to incomplete type 'struct X[]'    main.c    /struktura/src    line 16    C/C++ Problem


Kako da mi ostane operator sizeof (pošto ne mogu da znam koliko će biti članova u nizu), a da opet menjam to samo na jednom mestu?

Code:

// heder.h
#ifndef HEDER_H_
#define HEDER_H_

struct X {
    int a;
    int b;
};

#endif /* HEDER_H_ */


Code:

// prvi.c
#include "heder.h"

struct X nizX[] = {
        [0] = {
                .a = 1,
                .b = 2,
        },
        [1] = {
                .a = 3,
                .b = 4,
        },
        [2] = {
                .a = 5,
                .b = 6,
        },
};


Code:

// main.c
#include <stdio.h>
#include "heder.h"

extern struct X nizX[];

int main() {

    int i;
    for (i = 0; i < sizeof(nizX)/sizeof(struct X); i++) {
        printf("%d %d\n", nizX[i].a, nizX[i].b);
    }

    return 0;
}
[ deerbeer @ 28.03.2012. 11:19 ] @
Umesto ovog :
Code:

for (i = 0; i < sizeof(nizX)/sizeof(struct X); i++) {
        printf("%d %d\n", nizX[i].a, nizX[i].b);
    }

valjda ide ovo :

Code:

extern struct X nizX[3]; 

for (i = 0; i < sizeof(nizX)/sizeof(X); i++) {
        printf("%d %d\n", nizX[i].a, nizX[i].b);
    }


Primecujes razliku ?


[Ovu poruku je menjao deerbeer dana 28.03.2012. u 12:39 GMT+1]
[ Texas Instruments @ 28.03.2012. 11:46 ] @
Mislim da grešiš. Probaj da iskompajliraš to što si napisao i videćeš da neće znati šta je X. A i druga stvar je što meni treba nešto što mi neće zavisiti od broja elemenata niza (ne mogu da znam hoće li bit 1, 2, 3 ... 10 elemenata).
[ deerbeer @ 28.03.2012. 12:06 ] @
Probao i kompajlira se sa msvc kompajlerom . Sto ne stavis to kao static varijablu i X i nizX u header fajl i proci ce sigurno ?


header.h

Code:
 
#pragma once  

struct X {
    int a;
    int b;
};

 static X nizX[] = {
        {
           1,
           2,
        },
        {
           3,
           4,
        },
        {
           5,
           6,
        },
 } ; 



[Ovu poruku je menjao deerbeer dana 28.03.2012. u 13:25 GMT+1]
[ deerbeer @ 28.03.2012. 12:24 ] @
Eh radi sa extern samo je bila mala zabuna
Kad si napisao :
Code:

extern X nizX [] ;  

Ti si ustvari deklarisao niz nizova od X i nije znao njegovu velicinu

Ako stavis :
Code:

extern X nizX ;  

On vec zna da je to niz koji je inicijalizovan i ne treba mu [] bas onako kako je @milanche napisao ..



[ Texas Instruments @ 28.03.2012. 12:38 ] @
Hajde iskopiraj tačno po fajlovima kako ti je definisano, pošto sad ne znam tačno šta si koristio. I druga stvar, msvc možda i radi, ali ovo treba da radi sa gcc-om, pošto je ovo program za neki MCU. ;)
[ deerbeer @ 28.03.2012. 12:53 ] @
header.h
Code:

#pragma once  
 struct X {
    int a;
    int b;
};


header.c
Code:

#include "header.h" 
 X nizX[] = {
        {
           1,
           2,
        },
        {
           3,
           4,
        },
        {
           5,
           6,
        },
};


u bilo kom *.c ili cpp

Code:

#include "header.h"  

extern X nizX ; 

for (i = 0; i < sizeof(nizX)/sizeof(X); i++) {
     printf("%d %d\n", nizX[i].a, nizX[i].b);
}


[ Texas Instruments @ 28.03.2012. 13:22 ] @
Veruj mi, ovo ne radi. Možda prolazi sa msvc-om, ali sa gcc-om ne može.
[ deerbeer @ 28.03.2012. 13:24 ] @
Ista greska (sizeof operator) ili nesto drugo ?
[ Texas Instruments @ 28.03.2012. 13:34 ] @
Sad sam probao i sa msvc-om da se uverim da radi kao što si napisao i ne može.
Code:

error C2061: syntax error : identifier 'nizX'
error C2059: syntax error : ';'
error C2065: 'nizX' : undeclared identifier
error C2065: 'X' : undeclared identifier

itd...


gcc se buni kod linije X nizX[] = { u header.c
Code:


Description    Resource    Path    Location    Type
expected '=', ',', ';', 'asm' or '__attribute__' before 'nizX'    header.c    /strukutra2/src    line 10    C/C++ Problem


Ne znam kako tebi to prolazi?
[ deerbeer @ 28.03.2012. 14:10 ] @
Hmm .. u pravi si izgleda printf ne radi tj. u kodu ne mozes koristiti [] operator jer extern nije definisan tako .
Ali ako si u debug vidi taj niz bez problema ...bas cudno .

Ja sam prvo bez njega kompajlirao misleci da je problem u sizeof-u pa je taj deo bio slucajno iskomentarisan .




Evo i projekta
[ deerbeer @ 28.03.2012. 14:37 ] @
Ono sto je zaobilazno resenje je da u header.c fajlu definises metode koje pristupaju nizu pa ti prakticno extern ni ne treba:
Dakle :

Code:
 
#pragma once  
 struct X {
    int a;
    int b;
};


X* getValue (int index ) ; 
int size () ; 





Code:

#include "header.h" 

struct X nizX[] = {
        {
           1,
           2,
        },
        {
           3,
           4,
        },
        {
           5,
           6,
        },
};


X* getX (int index ) 
{
    return &nizX[index] ; 
}

int size () 
{
    return sizeof (nizX) / sizeof(X) ; 
}



U kodu :

Code:

for (int i = 0; i < size();  i++) {
   
    printf("%d %d\n", getX(i)->a, getX(i)->b); 
        
}


Cak ni ovaj prethodni primer sa sizeof nije radio a debugu prikazuje sve lepo :)


BTW Ako kompajliras u vs2010 i za header.c fajl moras staviti u properties da se compile as (C++) kod.
Za Default ne prolazi. Ako nemas potrebe za c fajlovima koristi cpp extenizije i radice ti sa default .



[Ovu poruku je menjao deerbeer dana 28.03.2012. u 15:49 GMT+1]

[Ovu poruku je menjao deerbeer dana 28.03.2012. u 15:52 GMT+1]
[ milanche @ 28.03.2012. 15:32 ] @
Skoro sam imao istovetni problem sa GCC kompajlerom.

U gomili razlicitih kompajlera, sizeof() operator najcesce funkcionise u fazi kompajliranja
('at compile time'), pa u principu ima problem sa odredjivanjem velicine niza koji at compile
time nije razresen (tj. definisanjem da je 'extern' se naznacuje da postoji, a ko je tacno
u pitanju, odakle je rodom, kako se zove, da li je zenjen i ima li brkove...postaje kompletno
poznato tek u fazi linkovanja ('at link time')).

http://en.wikipedia.org/wiki/Sizeof

Citat:
It is the responsibility of the compiler's author to implement the sizeof operator in a way specific and correct for a given implementation of the language. The sizeof operator must take into account the implementation of the underlying memory allocation scheme to obtain the sizes of various datatypes. sizeof is usually a compile-time operator, which means that during compilation, sizeof and its operand get replaced by the result-value. This is evident in the assembly language code produced by a C or C++ compiler. For this reason, sizeof qualifies as an operator, even though its use sometimes looks like a function call. Applying sizeof to variable length arrays, introduced in C99, is an exception to this rule.


Ovaj problem se ne secam da sam mao sa VisualStudio kompajlerom, sto potvrdjuje
deo gornjeg citata da sizeof( ) moze da se implementira na razne nacine, a da je
najcesce compile-time operator.

Neko cross-platform ispravno resenje bi bilo da se u header-u definise nesto kao
Code:

#define BROJ_ELEMENATA_U_NIZU           (3)


pa da se koristi gde god bi se inace koristio sizeof(niz)/sizeof(element niza).


[ rikelme @ 29.03.2012. 01:24 ] @
http://c-faq.com/decl/extarraysize.html
[ Texas Instruments @ 29.03.2012. 10:12 ] @
Rikelme uleće klizeći i rešava sve nedoumice. :)
Hvala svima na pomoći.