Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.56/9: Рейтинг темы: голосов - 9, средняя оценка - 4.56
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915

Что делает директива include в связке с pragma once?

01.09.2023, 10:19. Показов 2012. Ответов 28
Метки c++ (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте,

Запутался совсем.

Что делает команда #include ?

Ну судя по тому, что говорит гугл - это простейшая операция скопировать-вставить, то есть берется весь код файла .cpp или .h и просто вставляется туда, где вызван #include - типа на этапе "препроцессора".

Вроде бы понятно. Непонятен другой момент - есть необязательная для с++ команда компилятора "pragma once" или из стандарта:
C++
1
2
3
4
#ifndef header_H 
#define header_H
...код
#endif
Который как бы должен не позволять включать код из файла два раза.

Я не могу понять, эти команды не позволять включать код более, чем один раз в любой файл, в котором вызван #include ?

Я это к тому, что говорят, что Only Header либы раздувают код, но ведь есть эти команды препроцессора, которые не позволяют включать код более одного раза ?
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
01.09.2023, 10:19
Ответы с готовыми решениями:

Что делает директива #pragma
а именно что выполняют эти строки? можно по-простому? #pragma package(smart_init) #pragma link "trayicon" #pragma resource...

Что делает директива #define ?
Что это значит? Задача с рядом Тейлора, 0.001 - это точность разложения. Опишите подробнее, почему так можно сделать? #define EPS 0.001

Директива #pragma
Хай кто обяснит для чего нужна директива #pragma option

28
Модератор
Эксперт С++
 Аватар для zss
13773 / 10966 / 6491
Регистрация: 18.12.2011
Сообщений: 29,245
01.09.2023, 10:46
Цитата Сообщение от Optimus11 Посмотреть сообщение
Only Header либы раздувают код
С чего бы это?
Я бы сказал, что наоборот, уменьшают код.
0
фрилансер
 Аватар для Алексей1153
6465 / 5678 / 1131
Регистрация: 11.10.2019
Сообщений: 15,118
01.09.2023, 10:47
Цитата Сообщение от Optimus11 Посмотреть сообщение
Что делает команда #include ?
препроцессор заменяет эту строку на содержимое файла, который указан в директиве

а #pragma once и/или гарды предотвращают повторные инклуды одного и того же файла внутри единицы трансляции
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
01.09.2023, 10:57
Цитата Сообщение от Optimus11 Посмотреть сообщение
Я не могу понять, эти команды не позволят включать код более, чем один раз в любой файл, в котором вызван #include ?
В те файлы где инклюд обрамлён логическим блоком проверяющим определение стража включения.

Цитата Сообщение от Optimus11 Посмотреть сообщение
Only Header либы раздувают код
Optimus11, обратите внимание на 2-й ответ:
"//**********************/questions/1165740/почему-не-все-c-библиотеки-header-only"

сайт не даёт опубликовать ссылку на стек оверфлоу)
тогда фраг:
Недостатки использования header-only библиотек:

Вы не можете скрыть детали реализации, как этого можно добиться при разделении библиотеки на интерфейс в виде .h файла и файла реализации поставляемого например в виде .lib, .dll.

Большинство изменений в библиотеке потребует перекомпиляции всех единиц компиляции, использующих эту библиотеку.

Более длительное время компиляции, так как компилятор должен видеть реализацию всех компонентов во включенных файлах, а не только их интерфейсы.

усложняется чтение кода, так как клиенту проще видеть только интерфейс используемого функционала и не отвлекаться на реализацию (спорное утверждение).

Нельзя слинковать динамически = нельзя заменить/обновить библиотеку в уже скомпилированной программе.
1
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
01.09.2023, 11:05  [ТС]
Цитата Сообщение от Алексей1153 Посмотреть сообщение
а #pragma once и/или гарды предотвращают повторные инклуды одного и того же файла внутри единицы трансляции
Не могу понять, что значит "повторные инклуды одного и того же файла внутри единицы трансляции".
"Единица трансляции" - это просто один файл ? Если да, то как внутри одного файла может оказаться несколько одинаковых нуклиидов?
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
01.09.2023, 11:06
разбухание - от необходимости компилировать определение в каждой единице трансляции. У чистых шаблонов (без финтов с явным инстанцированием) нет адреса, это не объекты кода и их нельзя связать.
0
фрилансер
 Аватар для Алексей1153
6465 / 5678 / 1131
Регистрация: 11.10.2019
Сообщений: 15,118
01.09.2023, 11:07
Цитата Сообщение от Optimus11 Посмотреть сообщение
то как внутри одного файла может оказаться несколько одинаковых нуклиидов
да запросто

1.cpp
#include "1.h"
#include "1.h"
#include "1.h"


Добавлено через 31 секунду
Цитата Сообщение от Optimus11 Посмотреть сообщение
нуклиидов
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
01.09.2023, 11:10
Цитата Сообщение от Optimus11 Посмотреть сообщение
Не могу понять, что значит "повторные инклуды одного и того же файла внутри единицы трансляции".
Optimus11, я уже мого раз повторял вам, - практикуйте и поймёте. Программирование нельзя выучить как букварь. Чтение текстов и просмотры видео не помогут.
На практике, повторное включение угрожает тогда когда есть ромбовидная структура включений. Один хедер включён в другой, а потом и он и другой включены в в какой-то сорс. Для исключения лишнего включения срабатывает страж.
1
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
01.09.2023, 11:11  [ТС]
Цитата Сообщение от Алексей1153 Посмотреть сообщение
да запросто

1.cpp
#include "1.h"
#include "1.h"
#include "1.h"
Ну блин - это ошибка программиста, какой смысл от этого защищать.

Наверное все таки от такого случая:


C++
1
2
3
4
5
6
7
8
9
header_1.h:
void func(){std::cout<<"func";}
 
my_cpp_1.cpp:
#include "header_1.h"
 
my_cpp_2.cpp:
#include "header_1.h"
#include "my_cpp_1.cpp"
Чтобы в my_cpp_2 дважды не включился код из header_1.h, через включение файла my_cpp_1.cpp ?
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
01.09.2023, 11:23
Цитата Сообщение от Алексей1153 Посмотреть сообщение
заменяет эту строку на содержимое файла
на содержимое заголовка.
заголовок может и не быть файлом.
1
фрилансер
 Аватар для Алексей1153
6465 / 5678 / 1131
Регистрация: 11.10.2019
Сообщений: 15,118
01.09.2023, 11:35
Цитата Сообщение от Optimus11 Посмотреть сообщение
это ошибка программиста, какой смысл от этого защищать.
нет, это не ошибка, такой инклуд может придти, будучи в составе другого инклуда, вложенного ещё в три инклуда. И от этого требуется защита

Цитата Сообщение от Optimus11 Посмотреть сообщение
#include "my_cpp_1.cpp"
а так делать не нужно
0
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
01.09.2023, 11:43  [ТС]
Цитата Сообщение от Алексей1153 Посмотреть сообщение
а так делать не нужно
Почему ?
0
фрилансер
 Аватар для Алексей1153
6465 / 5678 / 1131
Регистрация: 11.10.2019
Сообщений: 15,118
01.09.2023, 11:47
Optimus11, инклудят заголовки, а единицы трансляции для этого не предназначены
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,818
01.09.2023, 12:22
Цитата Сообщение от Optimus11 Посмотреть сообщение
Почему ?
Потому что cpp-файл - это основа для единицы трансляции в нем обычно находятся определения. ЕТ компилируется совместно со всеми include-ами, которые в нее добавили. Если вы включили cpp-файл через include, то получите две единицы трансляции с одинаковыми определениями (например в 1.cpp включили 2.cpp, следовательно содержимое 2.cpp будет скомпилировано два раза: первый раз в составе 1.cpp, а второй - когда уже сам 2.cpp будет компилироваться как ЕТ), а это приведет к нарушению ODR: в лучшем случае к ошибке линкера, а в худшем все соберется, но работать может неправильно.
Я же вот вам в 20-м году давал ссылку, где все это разъясняется. Вы ее не смотрели?
1
631 / 526 / 104
Регистрация: 05.08.2022
Сообщений: 2,810
01.09.2023, 12:24
Так много написано, и ни одного простого понятного примера. Сплошная терминология для тех, кто и так знает ответ.

Добавлено через 10 секунд
--1.h--
C++
1
2
3
Class1 {
.....
}
--2.h--
C++
1
2
3
4
5
6
#include "1.h"  // включаем этот заголовок здесь, т.к. будем использовать Class1; для "упростить использование", чтобы если в cpp включили только 2.h - то всё равно корректно комплировалось
 
Class2 {
.....
... используем Class1 ...
}

--main.cpp--
C++
1
2
#include "1.h"   // а ничто нам не запрещает включить оба эти include
#include "2.h"   // это даже выглядит логично, т.к. в коде будем использовать и Class1, и Class2
И вот при компиляции main.cpp (это и есть "единица трансляции") получается, что при включении 2.h изнутри него будет повторно включаться 1.h
Чтобы это предотвратить - и добавляют указанные защиты.

Второй вариант - без защит - внимательно следить за руками и не включать заголовки те, которые уже есть во включеных h-файлах.

Вообще, это философский вопрос: правильно (допустимо ли) инклудить одни h-файлы в другие?
Я встречался с двумя школами:

1) да, в h-файл следует включить все те h-файлы, от которых он зависит. Это упрощает подключение h-файлов при использовании в cpp

2) категорически недопустимо использовать #include в р-файлах! Резон как раз в том, чтобы
а) не было проблем с повторными включениями
б) не раздувать код вот этими неочевидными вложенными включениями всего и вся.

Теоретически я считаю, что подход школы 2) более правильный. Но он осложняется необходимостью очень хорошо проектировать h-файлы и необходимостью хорошо понимать в каком порядке требуется включать h-файлы в cpp, иначе если включить не в том порядке - то на момент компиляции 2.h мы еще не будем знать про Calss1 (в терминах приведённого выше примера), значит получим ошибку компиляции.

Поэтому на практике чаще видим подход школы 1), это проще в использовании и не требует аккуратности при проектировании h-файлов.
1
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,818
01.09.2023, 12:35
Цитата Сообщение от KSergey9 Посмотреть сообщение
Теоретически я считаю, что подход школы 2) более правильный. Но он осложняется необходимостью очень хорошо проектировать h-файлы необходимостью хорошо понимать в каком порядке требуется включать h-файлы в cpp.
Вот допустим ситуация: есть класс, в котором есть поле std::string. Вопрос, как без включения #include <string> описать этот класс в своем заголовочном файле?
C++
1
2
3
4
5
6
7
// some.h
class Some {
public:
    //.....
private:
    std::string m_name;
};
Насколько я понимаю, вы предлагаете делать так:
C++
1
2
3
4
5
6
7
// other.cpp
 
#include <string>
// обязательно перед ним сделать #include <string>
#include "some.h"
 
// использование class Some
Да? Если да, то чем же это лучше? Это невероятно сложный и ошибкоопасный микроконтроль за каждой единицей трансляции, где всегда нужно вручную учитывать порядок включения h-файлов.
Или вы что-то другое имели в виду?
0
фрилансер
 Аватар для Алексей1153
6465 / 5678 / 1131
Регистрация: 11.10.2019
Сообщений: 15,118
01.09.2023, 12:38
Цитата Сообщение от KSergey9 Посмотреть сообщение
1) да, в h-файл следует включить все те h-файлы, от которых он зависит
это правильный вариант
0
-41 / 49 / 5
Регистрация: 10.01.2017
Сообщений: 1,915
01.09.2023, 12:53  [ТС]
Цитата Сообщение от DrOffset Посмотреть сообщение
Я же вот вам в 20-м году давал ссылку, где все это разъясняется. Вы ее не смотрели?
Однако у Вас память. Если в 2020 и смотрел, то скорее всего ничего не понял. Попробую еще раз теперь.

Добавлено через 4 минуты
Цитата Сообщение от DrOffset Посмотреть сообщение
Или вы что-то другое имели в виду?
Если я правильно понял, то KSergey9 имел ввиду такое:

C++
1
2
3
4
5
6
7
8
my_func.h:
#include <string>
void my_func(std::string& string_ref);
 
my_func.cpp:
#include "my_func.h"
//Здесь include <string> - уже делать не надо, так как он есть в my_func.h
void my_func(std::string& string_ref){std::cout<<string_ref<<std::endl;}
0
631 / 526 / 104
Регистрация: 05.08.2022
Сообщений: 2,810
01.09.2023, 13:13
Цитата Сообщение от DrOffset Посмотреть сообщение
Да? Если да, то чем же это лучше?
Да.
Это принуждает к порядку.

Цитата Сообщение от DrOffset Посмотреть сообщение
и ошибкоопасный микроконтроль
Я не вижу опасности (вот именно опасности), ибо все проблемы вылезают на этапе компиляции.
Проблем при добавлении нового include - добавляет, да.

Добавлено через 27 секунд
Цитата Сообщение от Алексей1153 Посмотреть сообщение
это правильный вариант
Зависит от научной школы, которая на данный момент платит вам зарплату
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,818
01.09.2023, 13:30
Цитата Сообщение от KSergey9 Посмотреть сообщение
Это принуждает к порядку.
В большом проекте это превратится в ад. Беспорядок уже будет на уровне cpp, где первые несколько экранов будут только перечислены заголовочные файлы от которых он зависит, причем в строго определенном порядке, иначе все сломается.
А, допустим, изменение заголовочного файла приведет к ручному изменению всех cpp, куда он добавлен, опять же со строгим соблюдением порядка.

Эту идею можно конечно применять, например в сочетании с pimpl она хорошо работает, т.к. у такого pimpl-класса открытых зависимостей в принципе нет, поэтому и включать заголовочные файлы не обязательно. Однако тут уже вопрос применимости самого pimpl возникает, огульное его использование может серьезно помешать создать производительную программу.

Короче говоря, в классической системе раздельной компиляции С\С++ этому подходу почти нет места. В серьезных проектах он выльется в колоссальные трудозатраты по сопровождению кода, потому что по сути мы забрали у компилятора его работу и делаем ее теперь вручную.

Цитата Сообщение от KSergey9 Посмотреть сообщение
Зависит от научной школы
В мире, где такими вещами заправляет "школа" (почти как секта), а не обоснованная техническая потребность, лучше находиться как можно меньше.

Добавлено через 1 минуту
Цитата Сообщение от Optimus11 Посмотреть сообщение
Если я правильно понял, то KSergey9 имел ввиду такое:
Как он сам выше подтвердил, он имел в виду прямо противоположное.
2
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
01.09.2023, 13:30
Помогаю со студенческими работами здесь

Директива препроцессору #pragma
Что это за директива такая? Для чего предназначена? Если не затруднит, можно привести примеры?

Директива препроцессора pragma
Добрый день! Помогите, пожалуйста, не могу понять смысл такой записи. (интересуют строки с участием _PACKED(строки 2-6 и 51-60), и что...

директива #pragma. модификатор volatile. и функция system()
Всем привет! Скажите пожалуйста что делает директива #pragma Я знаю, что её значение зависит от компилятора, тогда подскажите где...

Чертовщина с #include guards и #pragma once
Господа, у меня тут творится какая-то хрень: что бы я ни делал, h-файл инклудится дважды и константы, описанные в нём, в разных модулях...

Директива #include
Всем привет. Пишу программу по книге Дейтел Х., Дейтел П - Как программировать на C++ FIG6_5.cpp, я компилирую проект FIG6_5.dev вместе с...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Как я обхитрил таблицу Word
Alexander-7 21.03.2026
Когда мигает курсор у внешнего края таблицы, и нам надо перейти на новую строку, а при нажатии Enter создается новый ряд таблицы с ячейками, то мы вместо нервных нажатий Энтеров мы пишем любые буквы. . .
Krabik - рыболовный бот для WoW 3.3.5a
AmbA 21.03.2026
без регистрации и смс. Это не торговля, приложение не содержит рекламы. Выполняет свою непосредственную задачу - автоматизацию рыбалки в WoW - и ничего более. Однако если админы будут против -. . .
Программный отбор значений справочника
Maks 21.03.2026
Установка программного отбора значений справочника "Сотрудники" из модуля формы документа. В качестве фильтра для отбора служит предопределенное значение перечислений. Процедура. . .
Переходник USB-CAN-GPIO
Eddy_Em 20.03.2026
Достаточно давно на работе возникла необходимость в переходнике CAN-USB с гальваноразвязкой, оный и был разработан. Однако, все меня терзала совесть, что аж 48-ногий МК используется так тупо: просто. . .
Оттенки серого
Argus19 18.03.2026
Оттенки серого Нашёл в интернете 3 прекрасных модуля: Модуль класса открытия диалога открытия/ сохранения файла на Win32 API; Модуль класса быстрого перекодирования цветного изображения в оттенки. . .
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-rectangles-sdl3-c. zip finish-rectangles-sdl3-cpp. zip
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие. Ссылка в Linux — это запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая ссылка» (hard link),. . .
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора ВВЕДЕНИЕ Выполняя задание на управление насосной группой заполнения резервуара,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru