undefined reference — DedSec Project
C linker undefined reference — εντοπισμός υλοποίησης που λείπει Γιατί η μεταγλώττιση περνά αλλά η σύνδεση αποτυγχάνει Η δήλωση συνάρτησης ενημερώνει τον μεταγλωττιστή C για τον τρόπο κλήσης…
C linker undefined reference — εντοπισμός υλοποίησης που λείπει
Γιατί η μεταγλώττιση περνά αλλά η σύνδεση αποτυγχάνει
Η δήλωση συνάρτησης ενημερώνει τον μεταγλωττιστή C για τον τρόπο κλήσης της, αλλά δεν δημιουργεί τον κώδικα της συνάρτησης. Κάθε αρχείο .c μετατρέπεται συνήθως σε ξεχωριστή μονάδα και ο linker συνδέει τα αντικείμενα και τις βιβλιοθήκες. Όταν λείπει το αντικείμενο που ορίζει τη συνάρτηση add, η μεταγλώττιση του main.c μπορεί να περάσει αλλά η σύνδεση αποτυγχάνει. Η προσθήκη ενός ακόμη header χωρίς τη σωστή υλοποίηση δεν αρκεί.
Αναπαραγωγή και επιδιόρθωση χωρίς δίκτυο — C11
Αποθήκευσε ως reproduce.sh και εκτέλεσε sh reproduce.sh σε Linux/Termux με διαθέσιμο C compiler. Όλα τα αρχεία δημιουργούνται σε προσωρινό κατάλογο. Η πρώτη σύνδεση αναμένεται να αποτύχει, ενώ η δεύτερη πρέπει να συμπεριλάβει και τις δύο μονάδες και να επιστρέψει κωδικό εξόδου μηδέν.
#!/usr/bin/env sh
set -eu
work=$(mktemp -d)
trap 'rm -rf -- "$work"' EXIT
cat > "$work/main.c" <<'C'
int add(int a, int b);
int main(void) { return add(2, 3) == 5 ? 0 : 1; }
C
cat > "$work/add.c" <<'C'
int add(int a, int b) { return a + b; }
C
if cc -std=c11 -Wall -Wextra -Werror "$work/main.c" -o "$work/broken" 2>"$work/error.log"; then
echo 'FAIL: missing object was incorrectly linked' >&2
exit 1
fi
cc -std=c11 -Wall -Wextra -Werror "$work/main.c" "$work/add.c" -o "$work/fixed"
"$work/fixed"
printf 'PASS: missing definition rejected; both translation units linked\n'
Διάγνωση σε μεγαλύτερο πρόγραμμα
Μεταγλώττισε χωριστά με cc -c main.c και cc -c add.c, έπειτα σύνδεσε τα αρχεία αντικειμένων. Όταν η συνάρτηση βρίσκεται σε στατική βιβλιοθήκη, η σειρά των object files και των επιλογών -l μπορεί να επηρεάσει το αποτέλεσμα σε GNU-style linkers. Το nm main.o εμφανίζει συχνά U add για μη επιλυμένο σύμβολο και το nm add.o εμφανίζει T add για υλοποιημένη συνάρτηση. Αν υπάρχει όνομα αλλά αποτυγχάνει η σύνδεση, εξέτασε διαφορά C/C++ linkage, ασυμβατότητα αρχιτεκτονικής και τη βιβλιοθήκη που πραγματικά επιλέχθηκε.
Στοχευμένες ασκήσεις
- Αφαίρεσε μόνο το add.c από την επιτυχημένη εντολή και πρόβλεψε σε ποιο στάδιο εμφανίζεται το σφάλμα. Ξεχώρισε ελλιπή δήλωση από ανύπαρκτη υλοποίηση.
- Μετονόμασε την υλοποίηση σε sum_values χωρίς να αλλάξεις τη δήλωση και παρατήρησε το σύμβολο που λείπει.
- Δημιούργησε στατική βιβλιοθήκη με ar rcs libmathlocal.a add.o και σύγκρινε διαφορετικές θέσεις της βιβλιοθήκης στη γραμμή σύνδεσης, όπου υποστηρίζεται.
- Εμφάνισε το αποθηκευμένο error.log πριν καθαριστεί ο δοκιμαστικός κατάλογος. Μην κρύβεις το σφάλμα μέσω αλλαγής των προειδοποιήσεων.
Παραδοτέα: αποτυχία πρώτης σύνδεσης, PASS στο πλήρες πρόγραμμα και εξήγηση της διαφοράς μεταξύ compiler και linker.
Τεκμηρίωση: https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html