лекция 7 (1161102), страница 2
Текст из файла (страница 2)
В Си# и Java то, что называется тд char – это двухбайтовое целое число в формате Unicode, при этом нет никакой совместимости с целочисленными типами данных, можно явно переводить только в ushort и обратно. В Си++ появился wchar_t, аналог unsigned short. В языках, которые служат для передачи данных, основной кодировкой стала UTF-8 (XML).
В современных языках просматривается тенденция к «юникодизации», при этом не допускается совместимость с целыми типами (только явные преобразования). А для поддержки национальных языков появляются специальные средства записи символов - \u хххх – запись в юникоде.
Указатели и ссылки
Указатель – аналог адреса. При рассмотрении указателей возникает ряд проблем:
-
Для чего они нужны?
В Паскале указатели использовались только для работы с динамическими тд, нельзя было, например, написать указатель на integer. Динамические типы данных обычно состоят из ссылки на другой динамический объект и некоторой хранимой информации (список, дерево) – основой служила запись. Допустимые операции в Паскаль:
- присваивание между указателями P:=P1
- инициализация new(P) – отведение памяти (аналог malloc, new в Си и Си++)
- удаление dispose (P) - удаление объекта, на который ссылался указатель (аналог free, delete в Си и Си++)
- разыменование P^ - сам объект
При этом не было никакой возможности смешивать объекты из динамической памяти со статическими или квазистатическими объектами, как следствие увеличивалась надежность языка.
В Модула2 (наследник Паскаль) есть специальный тип ADDRESS (аналог void* в Си и Си++), абстрактный не типизированный адрес, к которому можно привести любой указатель. Операция ADR (x) – аналогична &х.
Программисты на Си при разработке серьезных проектов используют свои отладочные библиотеки вместо стандартных, переписывая основные функции, работающие с указателями и динамическими объектами – программа работает медленней, зато надежней. Многих ошибок можно было бы избежать, если бы придерживались принципов из Ада и Паскаль:
-
фиксированный набор операций над указателями (см.выше)
-
объекты из динамической памяти не пересекаются с объектами не из динамической памяти
Основные проблемы, возникающие при работе с динамической памятью в любых языках:
-
неконтролируемых преобразований адресов и возможности взятия адреса от любой переменной)
-
проблема мусора (из-за оператора освобождения)
-
проблема висячих ссылок (из-за оператора освобождения)
При введении указателей появляется еще одна проблема – базового набора типов. Наличие абстрактного адреса, получения адреса указателя и преобразование указателя одного к другому – все это в совокупности позволяет обойти любое ограничение в системе типов. Иногда система типов может быть слишком жесткой, так в реальной жизни один объект может выступать в разных ролях - а во многих языках существует принцип – объект принадлежит одному и только одному тд. И именно для преодоления этого ограничения программисты и пытаются преобразовать указатели - T* = T1*.
Рассмотрим указатели из Паскаля (см. Выше) и Ада 83. В Аде:
type PT is access T; // Т либо запись, либо массив
x: PT;
x1: PT;
1) х:=х1; //можно присваивать
2)x:= new T; // можно инициализировать – отведение динамической памяти под объект, указатель на объект присваивается х
3) Пусть T record
a: integer
end record
x.a // допустимо, а например в Обероне указатели могли быть только на запись и х.а аналог х->а в Си++
х.all //аналог *х в Си и х^ в Паскале, в Обероне синтаксис указателей на записи такой же как в Ада
4) формально в стандарте языка нет операции освобождения динамической памяти из соображений надежности. Процесс автоматической сборки мусора ресурсоемкий и, кроме того, garbage collector начинает работать в непредсказуемые моменты времени, а Ада разрабатывалась как язык для встроенных систем реального времени. В Ада 83 введен стандартный модуль и в нем есть процедура UNCHECKED_DEALLOCATION(x) – неконтролируемое удаление памяти, используется там, где необходимо повысить эффективность. В система, где больше заботятся о надежности используется динамическая сборка мусора.
В Си#, Java – исключительно динамическая сборка мусора, так же и в управляемом Си++.
1 [..]- такая конструкция может стоять перед именем типа или класса, или метода – то это атрибуты (метаданные). С помощью атрибутов можно управлять поведением компилятора, в атрибутах может находиться самая разнообразная информация – справочная информация. Информация об атрибутах помещается в исполняемый текст, они доступны и во время исполнения – есть возможность передавать информацию об объектах в исходном тексте – это новая технология (раньше были COM – библиотеки, а к ним специальные TLB библиотеки, которые содержали информацию об объектах COM). В Си# и в Java ситуация с передачей информации называется reflection, соответствующие пространства имен описывают каким образом происходит reflection (отражение). Возможность получения всей информации во время выполнения делает программирование более безопасным и гибким.