Как подключить stdafx.h

0.8 – несколько распространенных проблем c++

Директива #define

Символические константы

С директивой препроцессора мы также уже знакомы. С ее помощью объявляются и определяются так называемые символические константы. Например:

#define N 100
#define HELLO "Hello. Answer the questions."

Когда перед компиляцией исходный код будет обработан препроцессором, то все символьные константы (в примере это N и HELLO) в тексте исходного кода на языке C будут заменены на соответствующие им числовые или строковые литералы.

Символические константы можно определять в любом месте исходного кода. Однако чтобы переопределить их (изменить значение), следует отменить предыдущее определение. Иначе возникнет предупреждение (но не ошибка). Для удаления символической константы используют директиву :

#include <stdio.h>
 
#define HELLO "Hello. Answer the questions.\n"
 
int main () {
    printf(HELLO);
    #undef HELLO
    #define HELLO "Good day. Tell us about.\n"
    printf(HELLO);
}

Если в этом примере убрать строку , то при компиляции в GNU/Linux появляется предупреждение: «HELLO» переопределён.

Символические константы принято писать заглавными буквами. Это только соглашение для удобства чтения кода.

Макросы как усложненные символьные константы

С помощью директивы можно заменять символьными константами не только числовые и строковые константы, но почти любую часть кода:

#include <stdio.h>
 
#define N 100
#define PN printf("\n")
#define SUM for(i=0; i<N; i++) sum += i
 
int main () {
    int i, sum = ;
 
    SUM;
    printf("%d", sum);
    PN;
}

Здесь в теле функции константа PN заменяется препроцессором на , а SUM на цикл . Такие макроопределения (макросы) в первую очередь удобны, когда в программе часто встречается один и тот же код, но выносить его в отдельную функцию нет смысла.

В примере выше PN и SUM являются макросами без аргументов. Однако препроцессор языка программирования C позволяет определять макросы с аргументами:

#include <stdio.h>
 
#define DIF(a, b) (a)>(b)?(a)-(b):(b)-(a)
 
int main() {   
    int x = 10, y = 30; 
 
    printf("%d\n", DIF(67, 90));
    printf("%d\n", DIF(876-x, 90+y));
}

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

Обратите внимание, что после имени идентификатора не должно быть пробела:. Иначе, он бы означал конец символической константы и начало выражения для подстановки

  1. Напишите программу, содержащую пару макросов: один вычисляет сумму элементов массива, другой выводит элементы массива на экран.
  2. Напишите программу, содержащую макросы с аргументами, вычисляющие площади различных геометрических фигур (например, квадрата, прямоугольника, окружности).

Константы, определенные препроцессором

Препроцессор самостоятельно определяет пять констант. От обычных (определенных программистом) они отличаются наличием пары символов подчеркивания в начале и конце их имени.

  • __DATE__ — дата компиляции;
  • __FILE__ — имя компилируемого файла;
  • __LINE__ — номер текущей строки исходного текста программы;
  • __STDC__ — равна 1, если компилятор работает по стандарту ANSI для языка C;
  • __TIME__ — время компиляции.

Если эти константы встречаются в тексте программы, то заменяются на соответствующие строки или числа. Т.к. это происходит до компиляции, то, например, мы видим дату компиляции, а не дату запуска программы на выполнение. Программа ниже выводит значение предопределенных препроцессором имен на экран:

#include <stdio.h>
 
#define NL printf("\n")
 
int main () {
    printf(__DATE__); NL;
    printf("%d",__LINE__); NL;
    printf(__FILE__); NL;
    printf(__TIME__); NL;
    printf("%d",__STDC__); NL;
}

Результат:

Dec 17 2023
7
e5_const.c
21:48:52
1

Подключение заголовочного файла stdafx.​h

Для подключения стандартной библиотеки в C обычно используется директива #include.​

Однако в проектах, которые используют предварительное объявление (precompiled headers), вместо включения отдельных заголовочных файлов можно просто подключить заголовочный файл stdafx.​h.​

Этот файл содержит все необходимые предварительные определения и директивы препроцессора.​

Для использования stdafx.​h необходимо его сначала создать и настроить в проекте.​

Затем его можно подключить с помощью указанной директивы и использовать стандартные функции и классы из стандартной библиотеки.​

В программировании на C для использования стандартной библиотеки часто требуется подключение соответствующих заголовочных файлов.​ Однако, для проектов, использующих предварительное объявление (precompiled headers), можно вместо этого использовать заголовочный файл stdafx.h.​

Этот файл содержит все необходимые предварительные определения и директивы препроцессора, что упрощает процесс компиляции и сокращает время сборки программы.​

В данном разделе мы рассмотрим, как правильно подключать заголовочный файл stdafx.​h и зачем он нужен в проекте на C .​

Далее мы расскажем о роли заголовочного файла stdafx.​h в проекте на C .​

2.​ Библиотеки и препроцессор

В разработке программ на C широко используются библиотеки, которые содержат набор функций и классов для решения различных задач.​

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

Препроцессор C отвечает за обработку директив препроцессора, таких как #include, которые указывают компилятору, какие заголовочные файлы подключить к программе.​

Однако, для использования стандартной библиотеки C можно вместо подключения отдельных заголовочных файлов использовать заголовочный файл stdafx.​h при использовании предварительного объявления.​

3.​ Роль заголовочного файла stdafx.​h

Заголовочный файл stdafx.h играет важную роль в проектах на C , использующих предварительное объявление (precompiled headers).​

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

При использовании stdafx.h, компилятор уже содержит предварительно скомпилированный код из этого файла, что экономит время компиляции.​

Благодаря использованию stdafx.​h, не нужно подключать отдельные заголовочные файлы каждый раз, когда они требуются.​

Все необходимые определения и директивы уже находятся в stdafx.​h, поэтому просто подключается этот файл и можно использовать стандартные функции и классы из стандартной библиотеки.​

Подключение заголовочного файла stdafx.​h является удобным и эффективным способом использования стандартной библиотеки в проектах на C с предварительным объявлением.​

Этот файл содержит все необходимые предварительные определения и директивы препроцессора, что упрощает процесс компиляции и сокращает время сборки программы.​

Подключение stdafx.​h позволяет избежать необходимости включения отдельных заголовочных файлов и повышает эффективность разработки и сопровождения кода.​

Использование stdafx.​h ⏤ это хорошая практика, которая позволяет упростить разработку программ на C и достичь лучшей производительности.​

Подключение заголовочного файла stdafx.​h ー важный шаг в процессе разработки на C , который следует учитывать при создании проектов.

Директивы условной компиляции

Так называемая условная компиляция позволяет компилировать или не компилировать части кода в зависимости от наличия символьных констант или их значения.

Условное выражение для препроцессора выглядит в сокращенном варианте так:

#if …
    …
#endif

То, что находится между и выполняется, если выражение при возвращает истину. Находится там могут как директивы препроцессора так и исходный код на языке C.

Условное включение может быть расширено за счет веток и .

Рассмотрим несколько примеров.

Если в программе константа N не равна 0, то цикл выполнится, и массив arr заполнится нулями. Если N определена и равна 0, или не определена вообще, то цикл выполняться не будет:

#include <stdio.h>
 
#define N 10
 
int main() {
    int i, arr100;
 
    #if N
        for (i = ; i < N; i++) {
            arri = ;
            printf("%d ", arri);
        }     
    #endif
 
    printf("\n");
}

Если нужно выполнить какой-то код в зависимости от наличия символьной константы, а не ее значения, то директива будет выглядеть так:

#if defined(N)

Или сокращенно (что тоже самое):

#ifdef N

Когда нет уверенности, была ли определена ранее символьная константа, то можно использовать такой код:

#if !defined(N)
    #define N 100 
#endif

Таким образом мы определим константу N, если она не была определена ранее. Такие проверки могут встречаться в многофайловых проектах. Выражение препроцессора может быть сокращено так:

#ifndef N

Условную компиляцию иногда используют при отладке программного кода, а также с ее помощью компилируют программы под конкретные операционные системы.

Препроцессор обрабатывает программу до компиляции. В двоичном коде уже отсутствуют какие-либо условные выражения для препроцессора. Поэтому в логическом выражении «препроцессорного if» не должно содержаться переменных, значение которых определяется в момент выполнения программы.

Использование заголовочных файлов стандартной библиотеки

Рассмотрим следующую программу:

Эта программа печатает «Hello, world!» в консоль с помощью . Однако эта программа никогда не предоставляла определение или объявление для , поэтому как компилятор узнает, что такое ?

Ответ заключается в том, что был предварительно объявлен в заголовочном файле «iostream». Когда мы пишем , мы запрашиваем, чтобы препроцессор скопировал всё содержимое (включая предварительные объявления для ) из файла с именем «iostream» в файл, выполняющий .

Ключевой момент

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

Подумайте, что бы произошло, если бы заголовок не существовал. Каждый раз, когда вы хотели бы использовать , вам приходилось бы вручную вводить или копировать все объявления, связанные с , в начало каждого файла, который использовал бы ! Для этого потребуется много знаний о том, как реализован , и потребуется много работы. Хуже того, если бы прототип функции изменился, нам пришлось бы вручную обновлять все предварительные объявления. Намного проще просто включить iostream с помощью !

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

Рисунок 1 – Диаграмма процесса сборки

Лучшая практика

Заголовочные файлы обычно не должны содержать определений функций и переменных, чтобы не нарушать правило одного определения. Исключение сделано для символьных констант (которые мы рассмотрим в уроке «4.14 – const, constexpr и символьные константы»).

Использование заголовка «stdafx.h» в C++ с примерами

meta http-equiv=»Content-Type» content=»text/html;charset=UTF-8″>¤Ð°Ð¹Ð» заголовка ÑодеÑÐ¶Ð¸Ñ Ð½Ð°Ð±Ð¾Ñ Ð¿ÑедопÑеделеннÑÑ ÑÑнкÑий ÑÑандаÑÑной библиоÑеки. ÐаголовоÑнÑй Ñайл Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð²ÐºÐ»ÑÑен в пÑогÑÐ°Ð¼Ð¼Ñ Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ Ð´Ð¸ÑекÑÐ¸Ð²Ñ Ð¿ÑедваÑиÑелÑной обÑабоÑки C «#include» . ÐÑе заголовоÑнÑе ÑÐ°Ð¹Ð»Ñ Ð¸Ð¼ÐµÑÑ ÑаÑÑиÑение « .h» .

СинÑакÑиÑ:

 #include  / "header_file" 

#include ÑказÑÐ²Ð°ÐµÑ ÐºÐ¾Ð¼Ð¿Ð¸Ð»ÑÑоÑÑ Ð´Ð¾Ð±Ð°Ð²Ð¸ÑÑ header_file в иÑÑоднÑй код пеÑед вÑполнением опеÑаÑоÑов пÑогÑаммÑ.

ÐаголовоÑнÑй Ñайл «stdafx.h»

ЭÑÐ¾Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²Ð¾ÑнÑй Ñайл ÑвлÑеÑÑÑ Ð¿ÑедваÑиÑелÑно ÑкомпилиÑованнÑм заголовоÑнÑм Ñайлом. ÐÑÐ½Ð¾Ð²Ð½Ð°Ñ ÑÐµÐ»Ñ ÑÑого заголовоÑного Ñайла â ÑокÑаÑиÑÑ Ð²ÑÐµÐ¼Ñ ÐºÐ¾Ð¼Ð¿Ð¸Ð»ÑÑии. ЭÑÐ¾Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²Ð¾ÑнÑй Ñайл обÑÑно иÑполÑзÑеÑÑÑ Ð² Microsoft Visual Studio.

Ðез заголовоÑного Ñайла stdafx.h:

РпÑиведенной ниже пÑогÑамме иÑполÑзÑÑÑÑÑ Ð´Ð²Ð° заголовоÑнÑÑ Ñайла, iostream и cmath. ÐаждÑй Ñаз, когда пÑогÑамма компилиÑÑеÑÑÑ, Ñо Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ компилÑÑии пÑогÑÐ°Ð¼Ð¼Ñ ÐºÐ°Ð¶Ð´Ñй заголовоÑнÑй Ñайл бÑÐ´ÐµÑ ÐºÐ¾Ð¼Ð¿Ð¸Ð»Ð¸ÑоваÑÑÑÑ Ñ Ð½ÑлÑ. Таким обÑазом, вÑÐµÐ¼Ñ ÐºÐ¾Ð¼Ð¿Ð¸Ð»ÑÑии одинаково Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ компилÑÑии.

C ++

 

ÐÑÑод

 GFG! 

С заголовоÑнÑм Ñайлом stdafx. h:

«stdafx.h» пÑигодиÑÑÑ, когда Ð¼Ñ ÑоÑим компилиÑоваÑÑ Ð¿ÑогÑÐ°Ð¼Ð¼Ñ Ñнова и Ñнова. Ðн должен бÑÑÑ Ð²ÐºÐ»ÑÑен в наÑало вÑÐµÑ Ñайлов заголовков, и ÑепеÑÑ Ð¿Ñи пеÑвой компилÑÑии пÑогÑÐ°Ð¼Ð¼Ñ ÑкомпилиÑÐ¾Ð²Ð°Ð½Ð½Ð°Ñ Ð²ÐµÑÑÐ¸Ñ Ð²ÑÐµÑ Ñайлов заголовков, пÑиÑÑÑÑÑвÑÑÑÐ¸Ñ Ð² пÑогÑамме, бÑÐ´ÐµÑ ÑоÑÑанена в Ñайле «stdafx.h». ТепеÑÑ ÐºÐ°Ð¶Ð´Ñй Ñаз, когда пÑогÑамма компилиÑÑеÑÑÑ, компилÑÑÐ¾Ñ Ð±ÐµÑÐµÑ ÑкомпилиÑованнÑÑ Ð²ÐµÑÑÐ¸Ñ Ñайлов заголовков из Ñайла «stdafx.h», а не компилиÑÑÐµÑ Ð¾Ð´Ð½Ð¸ и Ñе же ÑÐ°Ð¹Ð»Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ¾Ð² Ñ Ð½ÑÐ»Ñ Ñнова и Ñнова.

ÐÑимеÑ:

Ð ÑÑÑ Ð¿ÑогÑÐ°Ð¼Ð¼Ñ Ð²ÐºÐ»ÑÑен заголовоÑнÑй Ñайл «stdafx.h». ТепеÑÑ, когда пÑогÑамма ÑкомпилиÑована, cmath и iostream бÑдÑÑ ÑкомпилиÑÐ¾Ð²Ð°Ð½Ñ Ñ Ð½ÑлÑ, а ÑкомпилиÑÐ¾Ð²Ð°Ð½Ð½Ð°Ñ Ð²ÐµÑÑÐ¸Ñ cmath и iostream бÑÐ´ÐµÑ ÑоÑÑанена в Ñайле «stadafx.h». ÐÐ»Ñ ÑледÑÑÑей компилÑÑии компилÑÑÐ¾Ñ Ð°Ð²ÑомаÑиÑеÑки вÑбиÑÐ°ÐµÑ ÑкомпилиÑованнÑÑ Ð²ÐµÑÑÐ¸Ñ ÑÑÐ¸Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²Ð¾ÑнÑÑ Ñайлов из заголовоÑного Ñайла «stadafx».

C++

 

 

 

9004;

 

ÐÑвод:

 prog.cpp:5:20: ÑаÑалÑÐ½Ð°Ñ Ð¾Ñибка: stdafx.h: Ð½ÐµÑ Ñакого Ñайла или каÑалога
компилÑÑÐ¸Ñ Ð¿ÑекÑаÑена. 

Заголовки и их назначение

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

Исходные файлы кода C++ (с расширением .cpp) – это не единственные файлы, которые обычно встречаются в программах на C++. Другой тип файлов – это заголовочный файл (иногда просто заголовок). Заголовочные файлы обычно имеют расширение .h, но иногда вы можете встретить их с расширением .hpp или вообще без расширения. Основная цель заголовочного файла – распространять объявления в исходные файлы кода.

Ключевой момент

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

Включение заголовочного файла в соответствующий исходный файл

Позже вы увидите, что большинство исходных файлов включают свой соответствующий заголовочный файл, даже если он им не нужен. Зачем?

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

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

При разработке библиотеки включение заголовочного файла в исходный файл может даже помочь в раннем обнаружении ошибок.

Лучшая практика

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

Директивы условной компиляции

Следующий набор
директив, который мы разберем, — это, так называемые, директивы условной компиляции:

#if,
#endif, #elif, #else, #ifdef, #ifndef, #elifdef, #elifndef

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

#define LANG_C
 
#if defined(LANG_C)
#   include <stdio.h>
#else
#   include <iostream>
#endif
 
int main(void)
{
         int x=5;
#ifdef LANG_C
         printf("%d\n", x);
#else
         std::cout << x << std::endl;
#endif
 
    return ;
}

Смотрите,
вначале определено макроимя LANG_C с помощью
директивы #define. Затем,
прописана директива #if, в которой проверяется условие:
определено ли макроимя LANG_C в текущем
модуле. Если это так (как в нашем примере), то макропроцессор оставляет в
программе все, что записано после этой директивы либо до следующей условной
директивы, либо до директивы #endif. В приведенном примере, остается
строчка «#   include <stdio.h>» и
удаляется строка «#   include <iostream>».
Соответственно, директива #include также, затем, обрабатывается
макропроцессором. В итоге, после обработки, у нас получается следующий текст программы:

#   include <stdio.h>
 
int main(void)
{
         int x=5;
         printf("%d\n", x);
 
    return ;
}

Разумеется,
директива #include здесь также
впоследствии преобразуется макропроцессором. А директива #ifdef – это
сокращенный вариант записи конструкции #if defined.

По сути,
директивы условной компиляции #if, #else, #endif работают
подобно условным операторам if-else, о которых мы с
вами уже говорили. Но, конечно же, есть и отличия. Первый важный момент: в
условиях директив можно использовать исключительно целочисленные литералы и
макроимена. С этими элементами можно выполнять все булевы операции сравнения:

==, !=, <,
>, <=, >=

логические
связки:

&&, ||,
!

все бинарные арифметические
и битовые операции:

+, -, *, /, %,
&, |, ^

и применять
оператор defined, которые
возвращает 1, если указанное макроимя существует и 0 – в противном случае. Есть
еще несколько экзотических конструкций, вроде условной тернарной операции,
которые допустимо прописывать в условиях директив, но в основном используются
те операции, что перечислены выше

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

Второй важный
момент. Директивы условной компиляции не образуют своих собственных внутренних
блоков. Поэтому для указания того, что попадает внутрь таких директив, в конце
обязательно следует прописать директиву #endif – метку,
означающую конец текущей директивы условной компиляции.

Третий важный
момент. Директивы препроцессора анализируют программу как текст (на уровне
лексем). Это означает, что они не учитывают области видимости: локальные,
глобальные и т.п. Поэтому все директивы принято записывать с самого начала
строки (с левого края). В частности, именно поэтому символ # у директив include записан на
одном уровне с другими директивами, т.к. никакого реального вложения здесь нет,
и это мы подчеркиваем оформлением. То же самое при записи директив внутри
функции main(). Для всех
этих директив функции не имеют никакого значения – это просто текст. Поэтому
все они прописаны с самого начала строки.

Рекомендации по использованию заголовочных файлов

Вот еще несколько рекомендаций по созданию и использованию заголовочных файлов.

  • Всегда включайте защиту заголовков (мы рассмотрим это в следующем уроке).
  • Не определяйте переменные и функции в файлах заголовков (глобальные константы являются исключением – мы рассмотрим их позже)
  • Давайте файлам заголовков те же имена, что и исходным файлам, с которыми они связаны (например, grades.h идет в паре с grades.cpp).
  • Каждый заголовочный файл должен иметь конкретное назначение и быть максимально независимым. Например, вы можете поместить все объявления, относящиеся к функциональности , в A.h, а все объявления, относящиеся к функциональности , в B.h. Таким образом, если позже вам нужен будет только , вы можете просто включить A.h и не получать ничего, связанного с .
  • Учитывайте, какие заголовки вам нужно явно включить для функций, которые вы используете в своих файлах исходного кода.
  • Каждый заголовок, который вы пишете, должен компилироваться сам по себе (он должен включать с все необходимые зависимости)
  • Включайте с только то, что вам нужно (не включайте всё только потому, что вы можете).
  • Не включайте с файлы .cpp.
Понравилась статья? Поделиться с друзьями:
Опытный компьютерщик
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: