Pierwsze pytanie dotyczy poprawnego includowania plików w c;
Mam program main.c, w ktorym jest tylko funkcja main, wywołująca inne funkcje które są zadeklarowane w pliku functions.h , i w nagłówku main.c mam #include “functions.h”.
Działać działa, ale czy tak sie poprawnie robi? Czy może w pliku functions.h powinienem umiescic prototypy funkcji a następnie w pliku functions.c właściwe funkcje?
Drugie pytanie, jak zrobić makefile do tego programu. Czy mając jeszcze zaincludowaną biblioteke math.h musze dopisać (gcc -ansi) -lm? A co z innymi funkcjami typu string.h, czy one też potrzebują argumentu przy kompilacji?
W functions.h powinna być deklaracje, w functions.c definicje. Ale tak naprawdę w functions.h często sa zdefiniowane makra i chyba funkcje inline. Najlepiej przejrzyj pare zrodel np. biblioteki.
nie zapomnij dodac strażnika w pliku nagłówkowym (#indef functions_h #define functions_h bla bla bla #endif).
W makefile musi być wskazanie do wlasciwej biblioteki (lacznie z tym czy 32 bity czy 64 bity i we wlasciwej arch cpu), w której jest skompilowany math.c. Jak tego nie będzie, będziesz miał blad linkowania do kupu.
Co dopisać w gcc - już nie pamiętam. Jeżeli chodzi o makefile, pamiętaj ze tam istotne sa tabulacje.
I teraz jeszcze pytanie co do includowanie bibliotek. Jeśli w mainie potrzebuje stdio, i w funkcje.c też (bo są używane scafny, printfy) to includuje i tu i tu? I analogicznie jesli nie potrzebuje w mainie a potrzebuje w definicjach funkcji, to tylko w definicjach includuje?
Jestem za tym, żeby w każdym pliku, którym potrzebujesz danych deklaracji, po prostu je dołączyć i nie polegać na zależnościach tranzytywnych. Szczególnie jeśli zależność ta wynika z zewnętrznej biblioteki. Dziś jest, jutro nie ma i nagle między wersjami program przestaje się kompilować.
W wielu tutorialach znajdziesz też podejście, na zasadzie wymienienia wszystkiego czego potrzebujesz w nagłówku do analogicznego pliku z implementacją. Jest to słabe, bo w ten sposób nadmiernie uzależniamy interfejs od konkretnej implementacji. Np. co jeśli ktoś chce napisać program zgodny z twoim interfejsem (powiedzmy dwa razy szybszy) i nie wykorzystuje żadnych z tych rzeczy, które dołączasz. W ten sposób zmuszasz go do dołączenia zależności z których nie korzysta (najlepsze co w tym przypadku może zrobić, to popisać puste pliki i je dołączyć, żeby efektywnie się tego pozbyć).
Linkowanie do biblioteki libm to historyczna zaszłość, w której, aby móc wykorzystać funkcje matematyczne również w FORTRAN wydzielono je do osobnej biblioteki. string.h nie jest funkcją jest nagłówkiem. Nagłówki nie potrzebują żadnych argumentów linkera. Linkowanie następuje do prototypów funkcji, więc trudno powiedzieć, czy string.h deklaruje jakąś funkcję, której implementacja nie jest dostępna w libc. W każdym razie, jeśli dołączysz deklarację funkcji, kompilator musi też znać jej definicję, ale tylko wtedy, gdy jest ona wywołana. To może wyjaśniać, czemu nie potrzebujesz likować do libm, po prostu nie wywołujesz nic, co jest zadeklarowane w math.h, a nie byłoby dostępne z libc.
Np. to się wysypie z powodu braku linkowania:
#include <math.h>
int main() {
int x = 2;
sqrt(x);
return 0;
}
Zwraca
gcc main.c -o main
/tmp/ccQKA1kL.o: In function `main':
main.c:(.text+0x15): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status