Каким должен быть язык программирования? Анализ и критика Описание языка Компилятор
Отечественные разработки Cтатьи на компьютерные темы Компьютерный юмор Новости и прочее

Массивы, структуры, типы, классы переменной длины

Предыдущие рассуждения об объектах переменной длины мы для простоты связывали со строками. Как правило, строки — это массив типа «char» (так реализовано во многих языках). Ничто не мешает использовать массивы других типов:

// Конструктор массива типа Double
DoubleArr :: DoubleArr (DoubleArr* ptr, ...) {
   ptr = Выделить память в другом стеке (требуемый размер);
   ptr -> Инициализация объекта DoubleArr (...);
}
            Ранее мы рассмотрели, как объекты переменной длины можно разместить в стеке функции. Встаёт вопрос: этот объект является экземпляром какого типа? Раз объект может иметь неизвестную во время компиляции длину, то и тип или класс этого объекта может быть достаточно произволен по своей структуре. Например, тип/класс объекта может иметь не только поля переменной длины, но переменное количество этих полей. Массивы могут иметь не только произвольное количество элементов, но и произвольную размерность.

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

            Но можно уже сейчас порассуждать о некоторых возможных проблемах. Возьмём, к примеру, структуру:
cтруктура ФИО {
   строка  Фамилия;
   строка  Имя;
   строка  Отчество;
};
            Если бы строковые поля этой структуры имели бы фиксированный размер, то программе было бы легко определить, в каком месте начинается поле «Имя». Зная во время компиляции размер поля «Фамилия», мы знаем смещение поля «Имя». Если размер полей не фиксирован и не известен во время компиляции, то нужно иметь механизмы получения адресов полей структуры. Значит, в самой структуре должны иметься (в скрытом виде) указатели на поля структуры. Эффективным будет такое решение.
  • Поля фиксированного размера размещаются в начале структуры. Для них нет нужды вычислять смещение — оно известно во время компиляции.
  • Первое поле переменного размера тоже имеет смещение, известное во время компиляции. Для него нет нужды создавать указатель.
  • Последующие поля переменного размера должны иметь скрытый указатель на себя. Эти указатели имеют фиксированный размер и под них отводится место в начале структуры — там же, где и остальные объекты постоянного размера. Для N полей переменного размера понадобится N-1 указателей.
            Конструктор, создающий экземпляр такой структуры, должен заполнить указатели на поля переменной длины. При копировании экземпляров структур адреса, содержащиеся в таких структурах, должны приводиться к правильным; в С++ этим занимается конструктор копирования.

            Теперь рассмотрим случай, когда структура имеет переменной количество полей. К примеру, во многих странах нет понятия «отчество», а в Исландии нет фамилий: исландцы носят только имя и отчество. В некоторых странах люди могут иметь несколько имён и несколько фамилий. Всё это может привести к такому выводу: структура может иметь внутри себя безымянные поля. Переменное количество полей не позволяет дать им имена, известные во время компиляции. Вывод такой: надо иметь возможность обращаться к полям массива по номеру, как если бы это был массив. Например, так:
	ФИО.[3]
            Такая свобода имеет и обратную сторону медали. Когда должен проверяться тип поля: во время компиляции или это откладывается на время выполнения программы? Это зависит от такого, какую типизацию будет иметь язык — статическую или динамическую. В случае статической типизации возможно решение, аналогичное тому, как в языке C определяются типы аргументов функций с переменным числом аргументов:
void  f (float  a, char*  b, int  c, ...)
            Третий и последующие аргументы имеют тип «int». Так же и в структурах: последнее описанное поле можно сделать определяющим тип последующих полей.

            Приведённые выше рассуждения можно распространить не только на структуры, но и на классы.

            Читаем далее следующую статью: О хранении данных в стеке — вместо заключения.

Почитайте ещё:

Опубликовано: 2014.07.27, последняя правка: 2018.10.29    15:54

ОценитеОценки посетителей
   ▌ 0
   ████████████████████████████ 2 (66.6%)
   ██████████████ 1 (33.3%)
   ▌ 0

Отзывы

     2016/05/06 14:07, utkin          # 

Если бы строковые поля этой структуры имели бы фиксированный размер, то программе было бы легко определить, в каком месте начинается поле «Имя». Зная во время компиляции размер поля «Фамилия», мы знаем смещение поля «Имя». Если размер полей не фиксирован и не известен во время компиляции, то нужно иметь механизмы получения адресов полей структуры. Значит, в самой структуре должны иметься (в скрытом виде) указатели на поля структуры. Эффективным будет такое решение.

Так и есть. Программа "знает" кто и где заканчивается. Потому что поля всегда выравниваются к какому-нибудь кратному блоку. Например, 8 байт. И если там в структуре в строке 5 символов (и нуль в сишной), то 2 байта будут лежать "вхолостую". Поэтому чисто теоретически СТАТИЧЕСКИЕ записи (типа struct или record) в стек запихуемы. А вот как это реально в стеке или куче я точно сказать не могу. Насчет строк, которые должны меняться, конечно все не так однозначно. Вероятно, там находится ссылка, то есть адрес, где расположены символы. Но в таком случае размер тем более известен и Вы смело можете пихать любую структуру в стек. А вот как расположить в стеке данные, изменения которых нужно проводить динамически, это большой вопрос.

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

Ну в свете вышесказанного смещение в структуре известно всегда. И во время компиляции и после.

     2016/05/07 11:12, Автор сайта          # 

А вот как расположить в стеке данные, изменения которых нужно проводить динамически, это большой вопрос.

Конечно, большой вопрос. Поэтому в функциональном программировании так любят неизменяемые данные. Но, между прочим, на верхушке стеке можно иметь объект с динамически изменяемым размером. Он, конечно, единственный. Но тут есть интересный момент. Обычно, заголовочная часть данных размещается в начале этих данных, т.е. в области с наименьшим адресом:
struct X {
int len;
char str[??];
};
В архитектуре x86 стек растёт вниз, в сторону уменьшения адресов. Т.е. заголовочная часть (поле len) данных окажется внизу. Если удлиняем стек, чтобы увеличить длину данных (чтобы строка str имела теперь большую длину), то адрес вершина стека уменьшится. Но тогда мы вынуждены переместить заголовочную часть данных (len), сами данные (str), и только потом на освободившееся место записываем дополнительные данные.

     2016/05/11 09:17, utkin          # 

Но тут есть интересный момент. Обычно, заголовочная часть данных размещается в начале этих данных, т.е. в области с наименьшим адресом:

Это Паскалевская строка такая. А вот Сишная просто до нулевого байта и длина строки, до тех пор пока Вы не посчитаете реальный размер дойдя до конца, неизвестна.

     2016/05/11 10:42, Автор сайта          # 

Вот поэтому мне не нравится строки в Си, но нравятся в Паскале. Хорошо на эту тему писал Джоэл Спольски в «Назад, к основам». Я Вам когда-то давал ссылку.

Добавить свой отзыв

Написать автору можно на электронную почту
mail(аt)compiler.su

Авторизация

Регистрация

Выслать пароль

Карта сайта


Содержание

Каким должен быть язык программирования?

Анализ и критика

●  Устарел ли текст как форма представления программы

●  Русский язык и программирование

●  Многоязыковое программирование

Синтаксис языков программирования

Синтаксический сахар

●  Некоторые «вкусности» Алгол-68

●  «Двухмерный» синтаксис Python

●  Почему языки с синтаксисом Си популярнее языков с синтаксисом Паскаля?

●  Должна ли программа быть удобочитаемой?

●  Стиль языка программирования

●  Тексто-графическое представление программы

●●  Разделители

●●  Строки программы

●●  Слева направо или справа налево?

●  Комментарии

●●  Длинные комментарии

●●  Короткие комментарии

●●  Комментарии автоматической генерации документации

●●  Нерабочий код

●●  Помеченные комментарии

●  Нужны ли беззнаковые целые?

●  Шестнадцатиричные и двоичные константы

●  Условные операторы

●  Переключатель

●  Циклы

●●  Продолжение цикла и выход из него

●  Некошерный «goto»

●  Изменение приоритетов операций

●  Операции присвоения и проверки на равенство. Возможно ли одинаковое обозначение?

●  Так ли нужны операции «&&», «||» и «^^»?

●  Постфиксные инкремент и декремент

●  Почему в PHP для конкатенации строк используется «.»?

●  Указатели и ссылки в C++

●●  О неправомерном доступе к памяти через указатели

●  Обработка ошибок

●  Функциональное программирование

●●  Нечистые действия в чистых функциях

●●  О чистоте и нечистоте функций и языков

●●  Макросы — это чистые функции, исполняемые во время компиляции

●●  Хаскелл, детище британских учёных

●●  Измеряем замедление при вызове функций высших порядков

●●  C vs Haskell: сравнение скорости на простом примере

●●  Уникальность имён функций: за и против

●●  Каррирование: для чего и как

●●  О тестах, доказывающих отсутствие ошибок

●  Надёжные программы из ненадёжных компонентов

●●  О многократном резервировании функций

●  Использование памяти

●  Почему динамическое распределение памяти — это плохо

●  Как обеспечить возврат функциями объектов переменной длины?

●●  Типы переменного размера (dynamically sized types, DST) в языке Rust

●●  Массивы переменной длины в C/C++

●●  Размещение объектов в стеке, традиционный подход

●●  Размещение объектов переменной длины с использованием множества стеков

●●  Размещение объектов переменной длины с использованием двух стеков

●●  Реализация двухстековой модели размещения данных

●●  Двухстековая модель: тесты на скорость

●●  Изменение длины объекта в стеке во время исполнения

●●  Размещение объектов переменной длины с использованием одного стека

●  Можно ли забыть о «куче», если объекты переменной длины хранить в стеке

●  Безопасность и размещение объектов переменной длины в стеке

●  Массивы, структуры, типы, классы переменной длины

●  О хранении данных в стеке, вместо заключения

●  Реализация параметрического полиморфизма

Описание языка

Компилятор

Отечественные разработки

Cтатьи на компьютерные темы

Компьютерный юмор

Новости и прочее




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

2024/04/19 22:13 ••• Автор сайта
Признаки устаревшего языка

2024/04/18 11:14 ••• Ivan
Энтузиасты-разработчики компиляторов и их проекты

2024/04/11 00:08 ••• Автор сайта
Постфиксные инкремент и декремент

2024/04/09 23:50 ••• Автор сайта
Русский язык и программирование

2024/04/07 15:33 ••• MihalNik
Все языки эквивалентны. Но некоторые из них эквивалентнее других

2024/04/01 23:39 ••• Бурановский дедушка
Новости и прочее

2024/04/01 23:32 ••• Бурановский дедушка
Русской операционной системой должна стать ReactOS

2024/03/22 20:41 ••• void
Раскрутка компилятора

2024/03/20 19:54 ••• kt
О многократном резервировании функций

2024/03/20 13:13 ••• Неслучайный читатель
Надёжные программы из ненадёжных компонентов

2024/03/07 14:16 ••• Неслучайный читатель
«Двухмерный» синтаксис Python

2024/03/03 16:49 ••• Автор сайта
О неправомерном доступе к памяти через указатели

2024/02/28 18:59 ••• Вежливый Лис
Про лебедей, раков и щук