Я немного запутался в файлах заголовков.
Насколько я понимаю заголовочные файлы в C, такие как #include <windows.h>, включаются только необходимые части в зависимости от того, какие функции используются в программе. Например, если бы в исходном коде была реализована только функция MessageBox(), то из заголовочного файла были бы включены только необходимые части.
Однако я наткнулся на WindowsHModular на GitHub здесь, который утверждает, что позволяет программисту включать только то, что требуется, поскольку автор GitHub разделил Windows.h на различные модули.
Это кажется довольно противоречивым, поэтому я надеялся, что кто-нибудь поможет мне разобраться в моих фактах.
Это должен быть повторяющийся вопрос... Файлы заголовков объявляют токены и прототипы функций, поэтому компилятор знает определенные значения и может сообщить о неправильном использовании. Последующее связывание — это когда код извлекается из библиотек и «связывается» вместе с вашей программой. C не импортирует код из заголовочных файлов.
Включение заголовочного файла почти равносильно замене директивы #include полным текстом включаемого файла. см. cprogramming.com/reference/preprocessor/include.html или en.wikibooks.org/wiki/C_Programming/…
@ Fe2O3 Что такое токен?
MessageBox()
не реализован в заголовочном файле. Заголовочный файл содержит только объявление, поэтому никакого кода не генерируется. Компоновщик должен заполнить таблицы импорта для каждого используемого импорта.
«Что такое токен?» демонстрирует потребность в том, чтобы вы сели за хорошую книгу по языку и начали учиться самостоятельно.
Токены @Fe2O3 не были описаны ни в Head First C, ни во 2-м издании языка программирования C... Судя по всему, токен может быть любым из следующих: ключевое слово идентификатор константа строковый литерал оператор пунктуатор
@IInspectable У вас есть ссылка на краткое объяснение того, как работают таблицы импорта для импорта?
Нет,
Если вы включаете файл строки
#include <file.h> // or "file.h"
Заменяется содержанием file.h
Пример: https://godbolt.org/z/a3WEP6hdP
Заголовочные файлы не являются библиотеками или объектными файлами. При компоновке компоновщик слинкует только используемую функцию (точнее все функции из используемых сегментов).
Но был бы мой окончательный размер исполняемого файла меньше, если бы я использовал WindowsHModular? Конечно, включая <windows.h> со всеми его сотни, а может быть, тысячи строк раздуют исполняемый?
Правильный файл .h не определяет никаких данных или функций. Он должен содержать только определения макросов, объявления типов данных, объявления внешних объектов и прототипы функций. .h файл может состоять из сотен тысяч строк, но он ничего не добавит к исполняемому файлу.
Итак, вы говорите, что даже если #include <file.h> помещает все из file.h в мой файл test.c, компоновщик удалит ненужные строки, добавленные file.h в test.c?
Эти строки не добавляют никакого кода в ваш исполняемый файл.
Вы сказали, что #include <windows.h>, который я использовал в качестве примера, будет заменен тысячами строк из файла windows.h, верно? Конечно, это увеличит размер исполняемого файла?
@securityauditor «конечно» не будет.
@securityauditor: ничего не добавляет к вашему исполняемому файлу. Размер исполняемого файла определяется компоновщиком, который будет включать только тот код, который фактически используется в вашем приложении. Заголовочный файл может определять тысячи функций, но если ваш код на самом деле не вызывает эти функции, они не будут связаны с вашим приложением.
@KenWhite на самом деле это не на 100% правильно. ld можно отбросить на уровне раздела, а не на уровне функции. Так что если функции в библиотеках и объектных файлах разместить в своих разделах, то будет работать так, как вы описываете. Если нет, то достаточно одной функции из раздела, чтобы использовать ее для всего размещения раздела. Поэтому при компиляции всегда размещайте функции в своих разделах.
«Разделы» не являются частью спецификации языка C. Это ld уступка откровению о том, что попытка масштабирования до бесконечности («каждый символ в открытом наборе по умолчанию общедоступен») не масштабируется. Комментарий @KenWhite точен с точки зрения клиента, использующего компоновщик, построенный на разумных принципах (например, MSVC link.exe).
Мое понимание файлов заголовков в C, таких как #include <windows.h>, заключается в том, что включаются только необходимые части в зависимости от того, какие функции используются в программе.
Я думаю, это зависит от того, что вы подразумеваете под «включено». Возможно, вы путаете включение заголовка со связыванием, которое является совершенно отдельным этапом позже в процессе компиляции.
На высоком уровне #include директивы просты. Они предписывают компилятору читать исходный код из другого файла, как если бы он появился вместо директивы. Вот и все. Нет врожденного выбора и выбора разных частей. Подумайте: как компилятор узнает, какие фрагменты вам нужны, прежде чем он обработает остальную часть исходного файла?
Принципиальной разницы между файлами заголовков и «обычными» исходными файлами нет, но стало общепринятым и очень строгим обычаем помещать в заголовки только определенные виды кода, в первую очередь:
struct
, union
и enum
определения типовtypedef
определенияВ основном это вещи, которые должны быть одинаково объявлены в нескольких независимых исходных файлах, и размещение их в файлах заголовков облегчает это и значительно упрощает обслуживание, когда один из них необходимо изменить.
Это также вещи, которые не влияют на программу, если они не используются. Например, результирующая программа не будет больше или сложнее, если источник объявляет функции, которые он никогда не вызывает, будь то с помощью #includeзаголовка или путем их объявления напрямую.
Тем не менее, я наткнулся на WindowsHModular на GitHub здесь, который утверждает, что позволяет программисту включать только то, что требуется, поскольку автор GitHub разделил Windows.h на различные модули.
Проблема с Windows.h в том, что он огромный и сложный. Хотя это не имеет значения для скомпилированных программ, это требует от компилятора значительных усилий. Цель разделения Windows.h на отдельные модули — сократить время ЦП и память, необходимые для компиляции программ, позволяя вам опустить кучу объявлений, которые вам все равно не нужны.
На данный момент вам, вероятно, лучше игнорировать WindowsHModular.
Но был бы мой окончательный размер исполняемого файла меньше, если бы я использовал WindowsHModular? Конечно, включение <windows.h> со всеми его сотнями, а может быть, тысячами строк приведет к раздуванию исполняемого файла?
Нет, @securityauditor, как я уже писал. Более того, десятки тысяч строк Windows.h и других заголовков, которые он сам включает, ни на йоту не увеличивают размер исполняемого файла. Внутри нет ничего исполняемого, только объявления. Объявления указывают компилятору, как интерпретировать другой код, но они не имеют собственного поведения во время выполнения.
Объявления @securityauditor не генерируют никакого кода. Они просто вводят символы для компилятора. И определения удаляются компоновщиком, если они не используются. Поскольку компоновщик MSVC по умолчанию использует частные символы, есть много возможностей для очистки.
it does make the compiler expend a fair amount of effort.
сейчас это кого-то волнует?
Удивительно, @0___________. Ясно, что автор WindowsHModular когда-то делал, и, возможно, делает до сих пор, так как проект обновлялся в течение последнего года.
@JohnBollinger есть zmilions бесполезных живых проектов
Да, @0___________, но вы не спросили, было ли это полезно. Вы спросили, волнует ли это кого-нибудь. Вы заметите, что я рекомендовал ОП игнорировать WindowsHModular. Мое мнение об усилиях компилятора заключалось в том, чтобы объяснить мотивацию такого проекта, а не приписывать ему полезность.
@JohnBollinger Я хотел показать OP, что не имеет значения, сколько строк в вашем файле .h.
@securityauditor Если вам небезразлично время компиляции, вы можете использовать символы препроцессора, чтобы ограничить поверхность API, которую компилятору придется обрабатывать (инструкции см. в разделе Более быстрые сборки с меньшими файлами заголовков).
@pmacfarlane Что, если бы я включил другой заголовок, например <stdio.h>, но никогда не использовал в исходном файле никаких функций, таких как printf()?