problem z typedef - pliki nagłówkowe .h

0

Dzień dobry.
Mam spory problem - potworzyłem definicje typu strukturalnego i w dalszym ciągu kod nie jest w stanie się skompilować.
Prośba o pomoc. Język C.

Plik main.c

#include <stdio.h>
#include "additional.h"
#include "config.h"

int main(int argc, char *argv[])
{

    return 0;
}

Plik config.h

#ifndef SRC_CONFIG_H_
#define SRC_CONFIG_H_

#include "additional.h"

typedef struct MyType
{
    int x;
} MyOwnType_t;

#endif /* SRC_CONFIG_H_ */

Plik additional.c

#include "config.h"

void foo(MyOwnType_t x)
{

}

Plik additional.h

#ifndef SRC_ADDITIONAL_H_
#define SRC_ADDITIONAL_H_

#include "config.h"

extern void foo(MyOwnType_t x);

#endif /* SRC_ADDITIONAL_H_ */

Kompilator wyrzuca błąd:
..\Src\additional.h:13:10: error: unknown type name 'MyOwnType_t'

Pomóżcie proszę.

3

additional.c powinien inkludować additional.h (i co do zasady każdy plik .c wciąga odpowiedni mu .h - jeżeli taki istnieje)

additional.h zawiera #include "config.h" więc additional.c nie musi tego robić, ale też nie powinno to zaszkodzić jeśli include guardy są robione odpowiednio.

config.h nie używa niczego z additional.h więc to #include "additional.h" wywal z config.h (w tej chwili inkludujesz config i additional w kółko).

Słowo extern w extern void foo() w additional.h nic nie robi, ale też nie szkodzi.

2

kompilacja: additional.c wiersz 1 dołączamy config.h
przechodzimy do config.h wiersz 3 dołączamy additional.h
przechodzimy do additional.h wiersz 4 znowu wołamy config.h ale strażnik SRC_CONFIG_H_ już zdefiniowany więc pomijamy
wracamy do additional.h wiersz 6 nie wiadomo czym jest MyOwnType_t

0

Dziękuję!
Ja błędnie zakładałem że kompilator rozpoczyna "robotę" od main.c, a tak naprawdę to chyba stara się przekompilować wszystkie pliki .c niezależnie.
Przeprowadziłem rozumowanie jak kolega @_13th_Dragon jednakże biorąc pod uwagę tylko plik main.c.
Dzięki za pomoc także @Azarien za pokazanie dobrych praktyk!

4
Adamos19 napisał(a):

Dziękuję!
Ja błędnie zakładałem że kompilator rozpoczyna "robotę" od main.c, a tak naprawdę to chyba stara się przekompilować wszystkie pliki .c niezależnie

Mniej więcej. Kompiluje w takiej kolejności w jakiej zostanie odpalony (łączeniem poszczególnych jednostek kompilacji (compilation units) zajmuje się linker, osobne narzędzie). Jeżeli korzystasz z makefile'a czy IDE typu Visual Studio to właściwie nie masz kontroli nad kolejnością kompilacji plików .c.

Traktuj każdy plik .c jako osobne odpalenie kompilatora, więc to co się dzieje podczas kompilacji main.c nie ma żadnego wpływu na kompilację additional.c.

0

@Azarien miałbym jeszcze jedno pytanie. Co sądzisz o moim pomyśle żeby stworzyć jeden plik config.h i w nim poinkludować wszystkie pozostałe pliki .h które istnieją w projekcie a później w każdym pliku .c inkludować jedynie config.h.
Zawsze tak robiłem i kod mi się kompilował. Teraz widzę że to jest niebezpieczne. Chciałbym abyś mi doradził jak kod można "odchudzić" - jeśli nie tak, to jak? Zawsze było to dla mnie bardzo wygodne bo nie musiałem we wszystkich plikach uzupełniać inkludów tylko jak pojawił się nowy plik .c i .h w projekcie, to po prostu do nowego pliku .c dodawałem inklude config.h, a do pliku config.h dodawałem inklude nowo powstały plik .h.
Czy można to jakoś sprytnie zrobić inaczej tylko bezpiecznie?

Ja wiem że to może być dla Ciebie masło maślane bo już mi wszystko powiedziałeś, ale i tak prosiłbym Cię o podpowiedź.

0
Adamos19 napisał(a):

nie musiałem we wszystkich plikach uzupełniać inkludów tylko jak pojawił się nowy plik .c i .h w projekcie

Ale dlaczego we wszystkich? Dodawaj tylko tam, gdzie chcesz użyć funkcji z tego nowego pliku.

0

Masz cykl include.
Wystarczy wywalić:

#include "additional.h"

z config.h
i działa: https://wandbox.org/permlink/LtS1ZaSknb2N4GNS

Im mniej include wewnątrz header files tym lepiej.
Powinno być tak: https://wandbox.org/permlink/bbu13Fht4X6M6mgV

0

Wszystko jasne, dzięki.
@Azarien - zamysł mój był taki aby utworzyć rozwiązanie full universalne i aby już nawet nie myśleć o tym które pliki mam inkludować a które nie.
Po prostu chciałem zrobić tak aby niezależnie w którym pliku .c się obracam, żebym mógł użyć dowolnej funkcji zdefiniowanej w dowolnym innym pliku .c.
Taki był zamysł.

0

No możesz tak zrobić, ale wydaje mi się że lepiej ograniczyć które funkcje są widoczne w danym momencie i w ogóle które są eksportowane na zewnątrz.

0

@Azarien: No tak, ale przecież to które z nich mają być eksportowane na zewnątrz a które nie to właśnie mam w pliku .h odpowiadającemu plikowi .c.
Tych których nie chcę widzieć na zewnątrz (czyli nie eksportować extern'em) po prostu nie będę umieszczał w odpowiadającym pliku .h.
Mam wrażenie że rozmawiamy o dwóch różnych rzeczach.
Z tym że rozwiązanie o którym mówiłem w poście o 13:17 nie działa czasem prawidłowo. Do dnia dzisiejszego tak zawsze robiłem i działało, dzisiaj miałem z tym problem. Nie mam za bardzo czasu wszystkiego analizować po kolei, na pewno jednak zrobię to później. Wiem na czym ten problem polega ale aby go rozwiązać (bo tu chodzi o inny grubszy projekt - to co napisałem to tylko przykładziki) muszę trochę przebudować mój soft i utracić taką uniwersalność o której marzę, a która do tej pory się sprawdzała.

0

Tak na marginesie, struct od daaawna uzyskało samodzielność, tzn nie trzeba się masakrować typedef-ami
To relikt, który dawno powinien odejść.

3
ZrobieDobrze napisał(a):

Tak na marginesie, struct od daaawna uzyskało samodzielność, tzn nie trzeba się masakrować typedef-ami
To relikt, który dawno powinien odejść.

Nie jestem ekspertem w temacie ale czy na pewno jest to prawdą w przypadku języka C? Który standard o tym mowi?

1
ZrobieDobrze napisał(a):

Tak na marginesie, struct od daaawna uzyskało samodzielność, tzn nie trzeba się masakrować typedef-ami
To relikt, który dawno powinien odejść.

To jest dość skomplikowana różnica między C a C++.
W C++ zdefiniowanie typu przez samo struct (albo class) ma efekt podobny co w C typedef struct. Upraszczając.

// C++
struct Foo {
};

Foo foo;
// C
typedef struct {
} Foo;

Foo foo;

Jeśli chodzi o C to spotkałem się z "coding rulesami" (i zgadzam się z nimi) by unikać robienia typedef struct, tylko definiować typy przez samo struct, jak w C++. Konsekwencją jest że potem trzeba zawsze pisać struct MyStruct podając nazwę typu, zamiast samego MyStruct.

// C
struct Foo {
};

struct Foo foo;
0
Azarien napisał(a):

Jeśli chodzi o C to spotkałem się z "coding rulesami" (i zgadzam się z nimi)

Jakie jest uzasadnienie tych rules?

1 użytkowników online, w tym zalogowanych: 0, gości: 1