Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
С и С++.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
212.63 Кб
Скачать

Структура компилятора

Процесс компиляции состоит из следующих этапов:

  1. Лексический анализ. На этом этапе последовательность символов исходного файла преобразуется в последовательность лексем.

  2. Синтаксический (грамматический) анализ. Последовательность лексем преобразуется в дерево разбора.

  3. Семантический анализ. Дерево разбора обрабатывается с целью установления его семантики (смысла) — например, привязка идентификаторов к их декларациям, типам, проверка совместимости, определение типов выражений и т. д. Результат обычно называется «промежуточным представлением/кодом», и может быть дополненным деревом разбора, новым деревом, абстрактным набором команд или чем-то ещё, удобным для дальнейшей обработки.

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

  5. Генерация кода. Из промежуточного представления порождается код на целевом языке.

В конкретных реализациях компиляторов эти этапы могут быть разделены или, наоборот, совмещены в том или ином виде.

3.Проблемы использования языка Си.

 в Си отсутствуют

  • вложенные функции;

  • сопрограммы;

а также, средства:

  • автоматического управления памятью;

  • объектно-ориентированного программирования;

  • функционального программирования.

Часть отсутствующих возможностей относительно легко имитируется встроенными средствами (например, сопрограммы можно имитировать с помощью функцийsetjmp и longjmp), часть добавляется с помощью сторонних библиотек (например, для поддержки многозадачности и для сетевых функций можно использовать библиотеки pthreads, sockets и т. п.; существуют библиотеки для поддержки автоматической сборки мусора[6]), часть реализуется в некоторых компиляторах в виде расширений языка (например, вложенные функции в GCC).

Многие элементы Си потенциально опасны, а последствия неправильного использования этих элементов зачастую непредсказуемы.  В связи со сравнительно низким уровнем языка многие случаи неправильного использования опасных элементов не обнаруживаются и не могут быть обнаружены ни при компиляции, ни во время исполнения. Это часто приводит к непредсказуемому поведению программы. Иногда в результате неграмотного использования элементов языка появляются уязвимости в системе безопасности. Необходимо заметить, что использования многих таких элементов можно избежать.

Примером ошибки является обращение к несуществующему элементу массива. Несмотря на то, что Си непосредственно поддерживает статические массивы, он не имеет средств проверки индексов массивов (проверки границ). Например, возможна запись в шестой элемент массива из пяти элементов, что, естественно, приведёт к непредсказуемым результатам. Частный случай такой ошибки называется ошибкой переполнения буфера. Ошибки такого рода приводят к большинству проблем с безопасностью.

Другим потенциальным источником опасных ситуаций служит механизм указателей. Указатель может ссылаться на любой объект в памяти, включая и исполняемый код программы, и неправильное использование указателей может порождать непредсказуемые эффекты и приводить к катастрофичным последствиям. К примеру, указатель может быть неинициализированным или, в результате неверных арифметических операций над указателем, указывать в произвольное место памяти; на некоторых платформах работа с таким указателем может вызвать аппаратную остановку программы, на незащищённых же платформах это может привести к порче произвольных данных в памяти, причём эта порча может проявиться в самые произвольные моменты времени и намного позже момента порчи. Также, область динамической памяти, на которую ссылается указатель, может быть освобождена (и даже выделена после этого под другой объект) — такие указатели называются «висячими». Или, наоборот, после манипуляций с указателями на область динамической памяти может не остаться ссылок, и тогда эта область, называемая «мусором» (garbage), никогда не будет освобождена, что может приводить к «утечкам памяти» в программе. В других языках подобные проблемы пытаются решить введением более ограниченных ссылочных типов.

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

Ещё одной распространённой проблемой является то, что память не может быть использована снова, пока она не будет освобождена программистом с помощью функции free(). В результате программист может случайно забыть освобождать эту память, но продолжать её выделять, занимая всё большее и большее пространство. Это обозначается термином утечка памяти. Наоборот, возможно освободить память слишком рано, но продолжать её использовать. Из-за того, что система выделения может использовать освобождённую память по-другому, это ведёт к непредсказуемым последствиям. Эти проблемы решаются в языках сосборкой мусора. С другой стороны, если память выделяется в функции и должна освобождаться после выхода из функции, данная проблема решается с помощью автоматического вызова деструкторов в языке C++, или с помощью локальных массивов, используя расширения C99.

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

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

4.Среда FrameWork. Связь Си++ и Си++/CLI. Отличительные особенности Си#.

 Framework — программная платформа, выпущенная компанией Microsoft в 2002 году. Основой платформы является общеязыковая среда исполнения Common Language Runtime (CLR), которая подходит для разных языков программирования. Функциональные возможности CLR доступны в любых языках программирования, использующих эту среду.

Считается, что платформа .NET Framework явилась ответом компании Microsoft на набравшую к тому времени большую популярность платформу Java компании Sun Microsystems (ныне принадлежит Oracle).

Хотя .NET является патентованной технологией корпорации Microsoft и официально рассчитана на работу под операционными системами семейства Microsoft Windows, существуют независимые проекты (прежде всего это Mono иPortable.NET), позволяющие запускать программы .NET на некоторых других операционных системах.

C# (произносится си шарп) — объектно-ориентированный язык программирования. Разработан в 1998—2001 годах группой инженеров под руководством Андерса Хейлсберга в компании Microsoft как язык разработки приложений для платформы Microsoft .NET Framework.

C# относится к семье языков с C-подобным синтаксисом, из них его синтаксис наиболее близок к C++ и Java.

C# разрабатывался как язык программирования прикладного уровня для CLR и, как таковой, зависит, прежде всего, от возможностей самой CLR. Это касается, прежде всего, системы типов C#, которая отражает BCL. Присутствие или отсутствие тех или иных выразительных особенностей языка диктуется тем, может ли конкретная языковая особенность быть транслирована в соответствующие конструкции CLR. Так, с развитием CLR от версии 1.1 к 2.0 значительно обогатился и сам C#; подобного взаимодействия следует ожидать и в дальнейшем (однако, эта закономерность была нарушена с выходом C# 3.0, представляющего собой расширения языка, не опирающиеся на расширения платформы .NET). CLR предоставляет C#, как и всем другим .NET-ориентированным языкам, многие возможности, которых лишены «классические» языки программирования. Например, сборка мусора не реализована в самом C#, а производится CLR для программ, написанных на C# точно так же, как это делается для программ на VB.NETJ# и др.

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