Неоднозначность в работе препроцессора и компоновщика

Пожалуйста, кто-нибудь развейте мои сомнения в том, что во время процесса компиляции препроцессор заменяет объявление предопределенной функции, но не определение, тогда почему мы не получили ошибку во время компиляции, что функция, не определенная как определение функции, добавляется в код после компиляции на этапе компоновки??

Подскажите, пожалуйста, как на самом деле работает препроцессор и связывание?

что ты имеешь в виду? Препроцессор ничего не знает об объявлении или определении функции.

phuclv 06.05.2024 07:19

Короче говоря и очень упрощенно, представьте себе препроцессор как программу, которая обрабатывает исходный файл перед реальным компилятором. Он выполняет замену копипастом включаемых файлов и макросов. Очень просто. Затем компилятор берет предварительно обработанный исходный код и компилирует его в объектный файл. Затем этот объектный файл передается компоновщику, который добавляет другие объектные файлы и библиотеки для создания окончательного исполняемого файла.

Some programmer dude 06.05.2024 07:20

Из моего описания должно быть ясно (надеюсь), что препроцессор на самом деле ничего не знает о самом коде, о операторах, объявлениях или определениях. Поэтому, пожалуйста, отредактируйте свой вопрос, чтобы показать нам минимально воспроизводимый пример кода, который вас интересует, и дайте нам более подробную информацию.

Some programmer dude 06.05.2024 07:21

Препроцессор выполняет в основном 3 задачи: 1. удаляет комментарии 2. расширяет макросы 3. включает содержимое заголовочных файлов, содержащих объявления библиотечных функций

KRISHNAKANT MALI 06.05.2024 07:22

если препроцессор включает содержимое файла заголовка, какой нужен компоновщику для связывания объектного кода файлов заголовков, если они уже присутствуют в коде

KRISHNAKANT MALI 06.05.2024 07:24
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
5
61
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Кажется, сейчас самое время узнать о концепции единиц перевода.

Подводя итог, единица перевода (или сокращенно TU) представляет собой единый исходный файл со всеми включенными заголовочными файлами. Это то, что на самом деле видит компилятор, и он ничего не знает о других единицах перевода.

Таким образом, если есть объявление функции, компилятор будет знать об этом, но если определение (реализация) находится в другом TU, то компилятор об этом не узнает. Компилятор может сгенерировать вызов функции, но оставить в объектном файле своего рода примечание о том, что в другой единице перевода есть ссылка на функцию.

Здесь на помощь приходит компоновщик: он принимает все единицы перевода (объектные файлы) и библиотеки и разрешает ссылки на функции в различных единицах перевода.


Сами заголовочные файлы никогда не «компилируются» сами по себе, они всегда включаются в исходные файлы. По сути, код заголовочного файла копируется в исходный файл.

Таким образом, как только препроцессор завершен, ни компилятор, ни компоновщик ничего не знают о файлах заголовков. Все, что они видят, — это отдельные единицы перевода.

спасибо за ответ, это прояснило мои сомнения, поскольку я пытался использовать функцию printf без использования #include<stdio.h> и просто объявлял функцию printf() для себя, и я получил желаемый результат с предупреждением. Но как в этом случае компоновщик узнайте, какой объектный код файла он должен был включить, поскольку я не добавлял ни одного файла заголовка

KRISHNAKANT MALI 06.05.2024 07:49

@KRISHNAKANTMALI Как я уже сказал, компоновщик вообще не знает о файлах заголовков. Но функция printf — это стандартная функция C, которая определена (реализована) в стандартной библиотеке C, связанной по умолчанию. Поэтому компоновщик найдет определение.

Some programmer dude 06.05.2024 07:55

@KRISHNAKANTMALI Также обратите внимание, что существует только одна стандартная библиотека C, но у нее много заголовочных файлов. Но может быть и наоборот, когда у вас есть один (или несколько) заголовочных файлов, но нет библиотеки, весь необходимый код находится в заголовочном файле. Таким образом, на самом деле нет никакой связи между файлами заголовков и библиотеками.

Some programmer dude 06.05.2024 07:57

Другие вопросы по теме