Саме тому, по одному лише ісходнику не можна визначити, які файли він вимагає для задоволення залежностей. Їх потрібно окремо, вручну, вказати лінковщік. З цієї причини з'явилися системи збирання - вони займаються тим, що стежать за оновленням файлів, Перекомпілюйте оновити і вказують лінковщік, які файли потрібно зв'язати. Пізніше, з появою IDE з'явилася необхідність в зберіганні інформації про взаємозв'язки файлів - так з'явилися проекти. По суті - просто список вихідних файлів, які потрібно відкомпілювати і зв'язати, а також інформація про налаштування компілятора / лінковщік / IDE.
Зовнішній символ об'вляется ключовим словом extern. Саме воно вказує компілятору, що не треба шукати реалізацію цього символу (або виділяти під нього місце, якщо це змінна). Функції є зовнішніми за замовчуванням, так що вказувати для них extern - необов'язково.
Наступна кумедна річ - множинні реалізації символу. Оскільки символ визначається тільки власним ім'ям (на відміну від модульних мов, де вказується не тільки сам символ, але і звідки його брати) - коли линкер зустрічає кілька однойменних символів, реалізованих в різних файлах, він не може визначити до якого з них відсилається компілятор і видає помилку. Звідси з'явилися танці, що забезпечують унікальність імен - префікси в С, простору імен в С ++.
Але крім випадкового збігу імен символів в різних файлах є ще одна причина появи цієї помилки - реалізація символу в заголовки. Якщо оголосити змінну або функцію (повністю, а не тільки її заголовок) - вона виявиться включена в усі файли, куди включено цей заголовки і, так як є і реалізація - то і реалізована в них усіх. Ну а далі, виявивши реалізації декількох однойменних символів линкер видасть помилку. Тому в заголовки поміщають тільки extern-змінні і заголовки функцій (за винятком inline функцій - їх на місце виклику підставляє сам компілятор, і тому повинен мати їх реалізацію в момент компіляції). Ще забавно виходить, якщо оголосити статичну (static - глобальна, але видно тільки в тому файлі, де оголошена) змінну в заголовочніке - все скомпілюється без помилок, але в кожному об'ектніке буде своя копія змінної, не пов'язана з іншими, хоча малася на увазі одна глобальна змінна . Як результат з'являється питання «а чому якщо я вантажу текстури в main.cpp, то все працює, а якщо в other.cpp - то текстури не Грузія?».
Ось. Якось приблизно так. Варто зауважити, в С ++ цей механізм ускладнений і працює трохи інакше, але я недостатньо з цими відмінностями знаком. Але, в першому наближенні, він працює схоже.
P.S. Чекаю гнилих помідорів від neiver'а та інших знавців С :)
Та нічого так.
Прикладів не вистачає)
в загальному бажано продовження про областях видимості і зі ввсемі витікаючими ...
і звичайно приклади повинні бути присутніми
Компактність мови С в поєднанні з великою кількістю операторів дає можливість створювати програмний код, розуміння якого надзвичайно важко. Ніхто не змушує програміста сoздавать незрозумілі програми, але всі можливості для цього є.
;)
під з # теж самі нюанси компіляції. на і в загальному для тих хто хоче вивчити сі з нуля з усім що тут обговорюється, йдіть книгу: Мова програмування Сі, Керниган, Рітчі. имхо краще для старту годі й шукати.
Хіба? Наскільки я знаю Шарп, від цього анахронізму там відмовилися і використовують щось на зразок модульної компіляції. Там начебто навіть заголовочніков зазвичай немає, підключаються .cs модулі або цілі .dll збірки. Його, все-таки, не стільки з З перли, скільки з Яви і дельфи.
А той факт, що програма використовує цю бібліотеку, доведеться окремо вказати лінковщік ... лінковщік треба вказувати object file? звідси інше питання - у обжект файлу і заголовки повинні бути однакові імена?
За правилами хорошого тону - так, взагалі необов'язково.
... а ще таке питання: якщо обжект файли знаходяться в тій-же папці що і проект, їх все одно треба вказувати лінковщік?
Так. Він їх сам не шукає. Він лінки ті файли, що вказано. Якщо вказано тільки ім'я - шукає в своїх директоріях пошуку. Ще об'єктні файли можуть перебувати в архіві - бібліотеці. Тоді її потрібно вказати Лінкер як бібліотеку - для gcc це -l gl.a. З бібліотеки він сам розбереться які файли включати (грубо кажучи - все, але «розумна лінковка» викине ті, на символи з яких немає посилань).
Звичайно, треба. Лінковщік про ваших проектах нічого не знає, він лінки, тільки те, що йому явно говорять, плюс стандартну бібліотеку.
До речі, проект сам по собі для того і призначений, щоб зберігати список об'ектніков і згодовувати їх лінковщік. Всі файли, що включені в проект (ну, звичайно, вони фільтруються по розширень, так що все .c і .cpp файли в проекті) будуть по порядку відкомпільовані і потім передані лінковщік.
До речі, в асемблері точно така ж система. Тому його досить легко поєднувати з С / С ++ - треба лише почитати як компілятор реалізує високорівневі штучки на кшталт передачі параметрів в / з функції. Хіба що видимі зовні символи там треба спеціально оголошувати з директивою GLOBAL (причому це залежить від конкретного асемблера). Зовнішні символи - тим же EXTERN.
... тоесть, одним словом - підстановкою всіх неізвесно імен функцій, змінних і т.д. в меін займається препроцесор, який в свою чергу шарить тільки в тих файлах що вказані Лінкер, тільки після закінчення зборки, функція меін транслірется в асемблер а потім Компільо?
.c -> .o -> .asm -> .hex або .exe - я правельно зрозумів?