Последние новости

YoungCoder теперь и на Stepikе. Записывайтесь: https://vk.cc/75rISy

Чтобы записаться на курс, необходимо зарегистрироваться на Степике: https://vk.cc/75rIC4

Это моя личная ссылка-приглашение на Stepik для вас. Регистрируясь по этой ссылке, записываясь на курсы и решая задачи, Вы помогаете автору данного сайта принять участие в конкурсе платформы Stepik! Подробности конкурса здесь: https://vk.cc/75rKuS

пятница, 14 ноября 2014 г.

Препроцессор языка Си. Директивы препроцессора.

Еще в самом первом уроке, я говорил вам, что когда компилятор встречает команду #include <stdio.h> он подставляет в это место содержимое файла stdio.h. На самом деле все немножко не так. Настал час, когда вас можно посвятить в эти тонкости, раньше они были излишними.
На самом деле, компилятор никакой строчки #include <stdio.h> никогда не встретит. Я уже упоминал, что процесс преобразования кода программы в исполняемый файл не так прост. Прежде чем передать код попадет к компилятору, его обрабатывает другая программа – препроцессор.
Препроцессор - это специальная программа, которая обрабатывает исходный код, прежде чем передать его компилятору.

 Чем занимается препроцессор?

  • удаляет комментарии из кода   
  • обрабатывает директивы препроцессора
Директивы препроцессора - это все те команды, которые начинаются с символа «#».
На данный момент вы знаете как минимум две такие команды #include и #define, хотя есть и другие.
Данный список неполный. Есть и другие действия, которые выполняет препроцессор, но я о них пока рассказывать не буду.
 

Как работает препроцессор?

В работе препроцессора важно понимать две вещи:
  • Препроцессор работает строго до компилятора
  • Препроцессор просто заменяет один текст – другим
Ему вообще наплевать на синтаксис и всякие условности. Он просматривает текст, и заменяет одни его кусочки другими.
Что и на что заменяется, вы уже должны знать, но я на всякий случай напомню.
В случае директивы #include <stdio.h> сама эта строка будет заменена препроцессором на содержимое файла stdio.h.
В случае директивы #define FJ 11 все вхождения FJ заменяются на 11. Кстати, это тоже не единственный вариант использования директивы #define. Но мы пока что коснемся только этого варианта.
Стоит отметить, что если FJ встретиться внутри имени какой-нибудь переменной или в названии оператора, то она естественно ни на что не заменится. Например, если есть переменная с именем kFJ, то она так и останется kFJ а не станет после обработки препроцессором k11.
Теперь разберем пример, который был в тесте в нашей группе во Вконтакте.


 Сразу же скажу правильный ответ. Да, эта программа скомпилируется и будет работать.
Теперь разберемся, почему же она будет скомпилирована.
Как я понял, большинство смутило то, что переменная s89 не объявлена, что и должно было бы привести к ошибке компиляции. Но, теперь вооружившись знаниями о работе препроцессора, разберемся, что же, на самом деле, получает компилятор для обработки.  Итак, сначала запускается препроцессор, который получает для обработки следующий код:


#include <stdio.h>
#define G s89
int main (){
        char G =10;
        s89=12;
        // комментарий
        printf("%d  %d\n", s89, G);
        return 0;
}

Препроцессор начинает  обрабатывать этот код и буквально сразу же встречает директиву #include <stdio.h>. Для него, как мы уже знаем, это команда на то, чтобы вставить вместо этой строчки содержимое файла stdio.h. Вставляем.  Получившийся код я сюда выписывать не буду, иначе это займет очень много места.
Препроцессор продолжает обработку файла и встречает команду #define G s89. Это как мы знаем, команда на то, чтобы заменить G на s89
После замены получим следующий код. (ниже приведен код только для функции main)

int main (){
        char s89 =10;
        s89=12;
       
        printf("%d  %d\n", s89, s89);
        return 0;
}

Ну и походу дела, препроцессор удалит комментарий из программы, а точнее заменит его пустой строчкой.
Вот, в принципе, мы и ответили на вопрос: «Почему программа компилируется?»
Хоть многих и смутило, что в ней отсутствует переменная s89, разобравшись обстоятельно, видим, что она-то как раз есть, а вот переменной G нет. Именно такой код поступит на компиляцию. Нетрудно видеть, что он корректный.

Как посмотреть код программы, после обработки препроцессором.

Дальше материал для тех, кому хотелось бы посмотреть полный код после обработки препроцессором Си. Такая возможность предусмотрена средой Visual Studio. Для этого нужно немножко поковыряться в свойствах проекта.
Ниже пошаговая инструкция:
1 шаг.
Открываем свойства проекта. Либо используем меню «Проект -> Свойства», либо горячие клавиши «Alt+F7».



2 шаг.
Слева, в появившемся окне выбираем «Свойства конфигурации -> С/С++ -> Препроцессор». 


Затем в правой части окна, в поле «Создавать файл препроцессора»  выбираем «Без номеров строк». Нажимаем «Ок».
Теперь, после нажатия «F7» в папке с проектом появится файл с расширением *.i открыв его в любом текстовом редакторе, вы и увидите файл после обработки препроцессором.
Стоит отметить, что при этом код не компилируется, и если вы попытаетесь запустить программу «Alt+F5» среда разработки предложит вам заново построить решение и только после этого запустит программу.
 

Внимание!
Пример, описанный выше сугубо показательный. Использовать такие выкрутасы в реальном коде недопустимо. Это легко может запутать того, кто будет потом читать ваш код.



Скачать текстовую версию урока. [pdf]

2 комментария :

Примечание. Отправлять комментарии могут только участники этого блога.