![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Что такое Самоадресуемая запись? [D6]
Tano © (2002-11-18 02:20:00)Насколько я понял, нельзя создать тип - массив записей (и тем более указатель на это).
type
TFieldID = record
Tp :TNodeType;
Offs :Integer;
HD :THD;
end;
TFieldsID = array[0..cMaxFieldsCount] of TFieldID;
pTFieldsID = ^TFieldsID; <- Error 59: "TFieldsID" is not a type identifier
при этом
var
FieldsID :array[0..cMaxFieldsCount] of TFieldID;
имеет право на существование, а
var
FieldsID :TFieldsID;
уже нет.
Компилятор разрешает объявление типа "массив записей", но как его использовать?
В моем карманном справочнике упоминается "Самоадресуемая запись", но "поскольку в книге не используются, рекомендуем [1] и [3]...".
Если кто знает, хотя бы подскажите ключевые слова на английском (все что могло прийти в голову уже перебрал и в Helpe и на форуме).
Thanks!
Tano (2002-11-20 09:00:00) [1]Мне не нужен большой размер!!!
Рассуждения пошли не в ту сторону.
Дело в том, что обсуждение 2Gb развернулось вокруг предельной верхней границы массива записей. Я просто хотел в качестве верхней границы выбрать заведомо достаточное мне (большое) число. Мне за глаза хватит 12800 байт на ЭТОТ массив - он у меня соответствует числу полей таблицы (100 полей - это уже бред!).
Я не собираюсь замахиваться на гигабайты виртуальной памяти. Просто у меня подобных структур больше десятка, обращаться приходилось таким методом (использую запись, указанную в subj):
type
PTFieldID = ^TFieldID; //указатель на запись
var
BasePtr :Pointer; //указатель на массив структур. память выделяется LocalAlloc
...
begin
...
ElementPtr:=BasePtr+ElementIndex*SizeOf(TFieldID);
//доступ к полю:
PTFieldID(ElementPtr)^.название_поля
теперь, когда все выяснил, могу писать:
//доступ к полю:
PTFieldsID(BasePtr)^[ElementIndex].название_поля
разница в одну строку, но так как подобные обращения очень частые, то гораздо эффективнее выглядит второй вариант, где сам Delphi генерирует оптимальный код для вычисления адреса.
На полном серьезе - так программа работает быстрее на 60%!
KSergey (2002-11-20 06:24:00) [2]простите, уточню: каждому процессу выделено 2Гб на все про все. Остальные 2 забраны системой, как верно сказал МBo.
Хотя у вас есть выход: если не ошибаюсь, в Win2k "старших" версий (типа Advdnce Server или что-то такое. проверять в книжке лень) процессу выделяется существенно больше - что-то вроде 64Гб (возможно, половину так же требует система - не вникал), да и не уверен, что это при плоской модели памяти.
Вот только на кой такие массивы бешенные?! Может как-то иначе к задаче подойти?
MBo (2002-11-20 06:01:00) [3]>32 разряда позволяют адресовать 4Gb памяти
пользователю доступно 2 гига, остальным распоряжается система
Tano (2002-11-20 04:42:00) [4]Кстати о 2Gb. Я вдруг вспомнил, что 32 разряда позволяют адресовать 4Gb памяти и внаглую потребовал выделить себе памяти 3Gb, 2.5Gb, 2Gb - не дают! Говорять, бери 1.3Gb и не пудри ядру мозги :-) /подкачка - 3.1Gb/. Пробовал командами LocalAlloc, VirtualAlloc.
Но это уже другая история...
Tano (2002-11-20 03:51:00) [5]Сдаюсь, сдаюсь, не нужно было ставить такую цифру!
Но Вы, Господин Anatoly Podgoretskyуж очень придирчивы (либо прочитали не все сообщения). Я уже написал, что:
1) Моя запись длиной 128 байт - ровнее некуда:
packed record //чтобы Delphi с перепугу поля не ровнял
Tp :TNodeType; //TNodeType = Byte; {1 байт}
Offs :Integer; {4 байта}
HD :THD; //THD = Integer; {4 байта}
Name :String[118]; {1+118 байт}
ИТОГО = 1 + 4 + 4 + (1+118) = 128
2) Выделение памяти контролирую сам.
Я для управления этой областью памяти вообще специально класс написал, где проверка на проверке, не говоря уже о счетчике элементов. А вопрос о указателе на массив записей возник из желания получать доступ к полям не через методы класса, а напрямую, побыстрее. Накладываю безразмерный массив на область памяти, проверяю допустимость индекса и читаю/пишу поле.
Даже в нашу эпоху гигагерцовых процов для определенных задач приходится считать и байты и такты. Для меня возможность сэкономить на вызове пары подпрограмм - уже значительный плюс. Не хочется попадать в ситуацию, когда на выцарапывание данных из памяти тратится больше времени, чем на их обработку.
В конце концов я использовал подсказку насчет array[0..0] (см. > han_malign © (19.11.02 10:46)).
Нижним мозгом чувствовал, что есть простое решение, но не хватило опыта :-).
Anatoly Podgoretsky (2002-11-19 21:20:00) [6]Только твоя запись, без учета на выравниваение, как минимум 131 байт и дико писать так, надо как минимум cMaxFieldsCount = (MaxInt div SizeOf(YourType)); при этом еще и резервировать минимум 16 байт для менеджера памяти, но и этого не достаточно, тебе выделено 2гб не для массива, а на все - на масиив на программу, на стек, на системные структуры и многое другое.
Ты же под один только массив запросил на 50 мб больше чем вообще доступно всего памяти.
Tano (2002-11-19 21:01:00) [7]
> han_malign © (19.11.02 10:46)
Великолепно! Это окончательно все проясняет. Насчет предела памяти я знал, поэтому и константу верхнего предела так считал (только моя запись 128 байт, но это не важно), но, похоже, это вышло коряво. Ваш пример позволит даже не думать об этом (при выделении памяти я сам проверяю диапазоны и возможность выделения памяти). Спасибо!
Термин Самоадресуемая запись я не придумал, а прочитал в довольно умной и толстой книге Архангельского "Программирование в Delphi 6" БИНОМ 2002 (п.15.16.1, последний абзац - если не верите :-). Спасибо что помогли внести ясность.
С динамическими списками я хорошо знаком, но нигде не встречал такого их названия.
Благодарю всех за помошь!
han_malign (2002-11-19 10:46:00) [8]Во первых: Static array typesare denoted by constructions of the form
array[indexType1, ..., indexTypen] of baseType
where each indexType is an ordinal type whose range does not exceed 2GB.
2GB=$80000000=2147483648, а твой массив получается 16777215*130=2181037950 - коментарии излишни.
Во вторых: самоадресуемая запись - неверный термин, есть самоадресуемый тип, пример приводился выше. Используется для создания связных списков. Примерно так Item<i+1> == Item .Next, при этом возмжен только последовательный доступ к елементам, немедленный по индексу невозможен. На таком же принципе строятся деревья, стеки, кольцевые списки, двусвязные списки, сети.
В третих: при {$R-}(по умолчанию Range checking отключен) достаточно
type
TFieldsID = array[0..0] of TFieldID;
PFieldsID = ^TFieldsID;
var _pFiledsID: PFieldsID;
begin
getMem(_pFiledsID,sizeof(TFiledsID)*N);
if(_pFiledsID<>nil)then begin//Memory allocated
................
with _pFiledsID[i] do ...
................
FreeMem(_pFiledsID);
end;
end;
- стринги здесь не причем просто в описании типа ты захотел больше памяти чем тебе может выделить Delphi.(в 16-битном Delphi не прошло бы даже array[0..65535]of byte, только array[0..65519]of byte (16 байт требовалось на описатель блока памяти))
Tano (2002-11-19 10:06:00) [9]Насчет своего последнего мессэджа - уверен (это написано в Helpe).
Кое-что проверил. Странноватая картина:
Мой массив записей был размерности [0..cMaxFieldsCount], где
const
cMaxFieldsCount = (MaxInt div 128); {= 1 6777 215}
так не работает, а если записать
const
cMaxFieldsCount = 1 5777 215;
то работает.
В общем, на успешность компиляции влияет числовое значение размерности. Странно, что выдается ошибка 59 (идентефикатор не является типом).
Я подобрал число, являющееся границей для моего случая (16 268 814) - единицей больше и возникает ошибка.
Изначально константу я считал как предельное теоретически возможное значение из расчета адресуемости 2Gb памяти.
В общем-то вопрос прояснился в отношении того как надо делать, но по поводу причины возникновения ошибки - подобранную константу не пойму (она меньше на 500kb чем 2Gb div 128).
Кстати, если просто взять ОЧЕНЬ большую константу (из области допустимых Int64), то пишет ошибку "Требуется перечисляемый тип" - вот это понять и предвидеть можно.
Walker (2002-11-19 06:27:00) [10]to MBo
вот как раз X(ИКС) его знает. Только помню что однажды, когда использовал типизированные файлы, а в качестве записи - record, одним полем которым был String[n] - компилятор выдавал ошибку. Я заменил String на ShortString - всё заработало.
MBo (2002-11-19 06:23:00) [11]Строка не мешает, все по-прежнему компилируется (кстати, объявленная таким образом - она является Shortstring)?
Tano (2002-11-19 03:25:00) [12]К сожалению, такое определение неверно.
ShortString - строка заготовленных 255 символов (и 0-й байт - длина), только в String[n] можно указать точный максимальный размер строки.
Walker (2002-11-19 01:38:00) [13]to Tano
попробуй написать так
Name: ShortString[118]
Tano (2002-11-18 21:13:00) [14]Поправка к моему сообщению (18.11.02 21:04): не строка размера 128 байт, а вся запись выровнена на 128 байт.
Tano (2002-11-18 21:11:00) [15]
> Sergic (18.11.02 20:57)
Это по виду элемент динамического списка, только PRec=^TRec.
Если Вы уверены, что это и есть загадочная самоадресуемая запись, то я разочарован :(. Thanks!
Tano (2002-11-18 21:04:00) [16]Дело в том, что у меня была в записи еще и переменная String[118]:
TFieldID = record
Tp :TNodeType;
Offs :Integer;
HD :THD; //THD = Integer;
Name :String[118];
end;
TFieldsID = array[0..cMaxFieldsCount] of TFieldID;
pTFieldsID = ^TFieldsID;
Извеняюсь, наверное надо было сразу вписать, но мне показалось, что смысл от этого не изменится. Ан нет!
Ведь строка, которая в записи имеет фиксированный размер 128 байт. Какая разница компилятору, для каких структур считать адреса ???
Без строки действительно компилируется.
> > ЮЮ © (18.11.02 04:53)
Простите за лаконичность (очень спешил). Мне нужно объявить указатель на массив записей, который можно наложить на динамически выделяемую область памяти. Указанный Вами метод я первоначально и использовал, но постепенно от него возникло мелких сложностей больше, чем преимуществ.
Сейчас я вручную вычисляю адрес i-того элемента и накладываю на него указатель на тип record. Работает нормально, только выглядит коряво.
И все-же, кто-нибудь знает о Самоадресуемой записи? Мне уже просто становиться интересно.
Sergic (2002-11-18 20:57:00) [17]Самоадресуемая запись это такая вот штука:
type
PRec=TRec
TRec=record
ID:longint;
Next:PREc;
end;
AngeL B. (2002-11-18 10:25:00) [18]
> 2 Tano:
Все написаное правильно и проходит компиляцию.
Проверь правильность написания всего. Возможна опечатка.
MBo (2002-11-18 08:02:00) [19]>Tano
у меня все это прекрасно компилируется в D5, хотя сомнений и так не было. Попробуй, что ли, объявление pTFieldsID раньше TFieldsID поставить
Tano (2002-11-18 07:52:00) [20]
> MBo © (18.11.02 06:16)
Синтаксически корректны, спору нет, но "Error 59..." - не плод моего больного воображения.
> ЮЮ © (18.11.02 04:53)
Не подходит