Форум: "Основная";
Текущий архив: 2005.06.29;
Скачать: [xml.tar.bz2];
ВнизДинамические массивы - правильно ли я понял help? Найти похожие ветки
← →
Ega23 © (2005-06-01 14:41) [0]Никогда не работал с дин.массивами. Хочется узнать - правильно ли я понял, как с ними работать?
Допустим:
var
a:array of Integer;
begin
SetLength(a, 5); // в массиве 5 элементов.
a[0]:=1; a[4]:5; // Индексация в массиве - с 0 до Length(a)-1
SetLength(a, 6); // Сохранились ли предыдущие значения a[0] и a[4]?
SetLength(a, 0) // Опреация по освобождению массива
end;
Так ли это?
← →
begin...end © (2005-06-01 14:43) [1]> Ega23 © (01.06.05 14:41)
> Сохранились ли предыдущие значения a[0] и a[4]?
Да.
> Опреация по освобождению массива
Если это уже конец подпрограммы, то это делать необязательно. Дин. массив освободится автоматически пр выходе из области видимости.
← →
TUser © (2005-06-01 14:43) [2]Все правильно. Элементы 0-4 сохранятся. + хорохо бы еще finally поставить.
Hint: Если массив объявлен как локальная переменная, то Delphi гарантирует освобождение памяти по завершении работы процедуры.
← →
Юрий Зотов © (2005-06-01 14:45) [3]> в массиве 5 элементов.
Да.
> Индексация в массиве - с 0 до Length(a)-1
Да. Еще можно использовать Low(a) и High(a).
> Сохранились ли предыдущие значения a[0] и a[4]?
Да. Сохранились вообще все элементы, включая и мусорные.
> Опреация по освобождению массива
Либо так, либо a := nil.
← →
Ega23 © (2005-06-01 14:46) [4]Спасибо всем.
← →
Ega23 © (2005-06-01 14:52) [5]Вдогонку ещё один вопрос:
Могу ли я после задания длины массиву (SetLength(a, Count)) использовать переменную a в виде буфера при чтении из Stream?
var
a:array of integer;
Count:Integer;
ms:TMemoryStream;
begin
ms:=TMemoryStream.Create;
try
TBLOBField(Query1.FieldByName("Data")).SaveToStream(ms);
Count:=Query1.FieldByName("DataLength").AsInteger;
ms.Position:=0;
SetLength(a, Count);
ms.ReadBuffer(a, Count*SizeOf(Integer));
......
finally
ms.Free;
a:=nil;
end;
end;
← →
Amoeba © (2005-06-01 14:54) [6]ms.ReadBuffer(a[0], Count*SizeOf(Integer));
← →
Ega23 © (2005-06-01 14:57) [7]А почему a[0]?
← →
begin...end © (2005-06-01 14:59) [8]> Ega23 © (01.06.05 14:57) [7]
Потому что иначе (как в коде [5]) ты будешь читать не в область, в которой расположены элементы массива, а в указатель на эту область.
← →
КаПиБаРа © (2005-06-01 14:59) [9]Ega23 © (01.06.05 14:57) [7]
Так нада.
a[0] - адрес первого элемента массмива
a - адрес где храится сцылка на a[0]
← →
begin...end © (2005-06-01 15:01) [10]> КаПиБаРа © (01.06.05 14:59) [9]
> a[0] - адрес первого элемента массмива
a[0] -- это не адрес. Это сам элемент.
← →
Ega23 © (2005-06-01 15:02) [11]Ага, спасибо. В общем, всё также, как и в "ручном" формировании динамического массива, только без GetMem - FreeMem
← →
evvcom © (2005-06-01 15:02) [12]
> А почему a[0]?
Потому что procedure ReadBuffer(var Buffer; Count: Longint);
Передаешь a[0] по ссылке, компилятор подставляет адрес 0-го элемента, если передавать a, то передашь адрес переменной a-указателя на динамический массив.
← →
evvcom © (2005-06-01 15:05) [13]
> только без GetMem - FreeMem
зато с (+) Length, Low и High, хотя для дин.массивов Low всегда = 0
← →
Ega23 © (2005-06-01 15:36) [14]Откровенно говоря, когда в университете проходили списки и способы их построения, всяческими array of и TList при написании заданий пользоваться было категорически запрещено.
Ну, TList я с тех пор худо-бедно освоил :)
А вот с массивами как-то не срослось. Да и надобности не было...
← →
Юрий Зотов © (2005-06-01 16:54) [15]> Ega23 © (01.06.05 14:52) [5]
Чтобы использовать что-то типаReadBuffer(a[0], Length(a) * SizeOf(тип_элемента))
массив, строго говоря, должен быть объявлен так:a: packed array of тип_элемента
Тут этот вопрос когда-то обсуждался и выяснилось, что компилятор пакует массивы даже и при отсутствии packed, но я бы все же рекомендовал указывать packed явно. Как минимум, по трем причинам:
- гарантирует от возможных коллизий в будущих версиях;
- дисциплинирует мозги;
- код становится прозрачнее.
← →
Ega23 © (2005-06-01 17:21) [16]
> a: packed array of тип_элемента
Спасибо. Это ценная информация.
Для статических массивов при описании структуры я packed использую, но про динамические - не знал.
← →
Суслик © (2005-06-01 17:25) [17]
> [15] Юрий Зотов © (01.06.05 16:54)
Знаешь, Юрий, на слово packed кладут, как мне показалось все, в том числе и сами разработчики borland. Такое ощущение, что они не собираются реализовывать соответствующую семантику вообще.
Я, кстати, всегда пишу, когда это нужно. Но есть ощущение, что это лишнее.
← →
Defunct © (2005-06-02 03:18) [18]Юрий Зотов © (01.06.05 16:54) [15]
> строго говоря, должен быть объявлен так:
> a: packed array of тип_элемента
скорее, не строго говоря, а в тех случаях когдатип_элемента
- record и не объявлен с ключевым словом packed либо не кратен 4.
a: packed array of integer
не красиво ;>
А вдруг (что маловероятно) первый элемент при этом окажется невыровняным на границу Dword? тогда работа с таким массивом на некоторых процессорах будет неоправдано медленной.
← →
begin...end © (2005-06-02 09:12) [19]> Defunct © (02.06.05 03:18) [18]
> скорее, не строго говоря, а в тех случаях когда тип_элемента
> - record и не объявлен с ключевым словом packed либо не
> кратен 4.
И на что в этом случае повлияет слово packed перед array?
← →
evvcom © (2005-06-02 09:27) [20]
> А вдруг (что маловероятно) первый элемент при этом окажется
> невыровняным на границу Dword
Первый уж точно будет выровнен, вот остальные ...
← →
Defunct © (2005-06-02 09:44) [21]> begin...end
не знаю. А что вы об это думаете?
> evvcom
там же ж слово packed, остальные будут будут "притиснуты" друг к другу.
← →
begin...end © (2005-06-02 09:45) [22]> Defunct © (02.06.05 09:44) [21]
> А что вы об это думаете?
Я думаю, что никак.
← →
begin...end © (2005-06-02 09:46) [23]В смысле, ни на что не повлияет.
← →
Defunct © (2005-06-02 09:54) [24]мне все-таки кажется, что хотя бы record к record"у прижмет вплотную.
← →
begin...end © (2005-06-02 09:55) [25]> Defunct © (02.06.05 09:54) [24]
А разве без packed перед array записи не будут прижаты друг к другу?
← →
evvcom © (2005-06-02 09:56) [26]
> там же ж слово packed, остальные будут будут "притиснуты"
> друг к другу
Я это знаю. Я говорил о варианте без packed.
← →
jack128 © (2005-06-02 09:57) [27]Defunct © (02.06.05 9:44) [21]
там же ж слово packed, остальные будут будут "притиснуты" друг к другу
не на всех платформах SizeOf(Integer) = Size(DWord). Хотя на это можно забить.
Defunct © (02.06.05 3:18) [18]
скорее, не строго говоря, а в тех случаях когда тип_элемента - record и не объявлен с ключевым словом packed либо не кратен 4
На самом деле если еще более абстрагироваться от конкретных платформ, то неупаковонный массив должен обеспечивать наиболее быстрый доступ к массиву. То что сейчас фактический это означает выравнивание на Dword не означает, что так будет в будущем...
Хотя разговор довольно бессмысленный так как
Суслик © (01.06.05 17:25) [17]
на слово packed кладут, как мне показалось все, в том числе и сами разработчики borland. Такое ощущение, что они не собираются реализовывать соответствующую семантику вообще.
← →
Defunct © (2005-06-02 10:01) [28]begin...end © (02.06.05 09:55) [25]
Возможены случаи когда не будут.
SizeOf(<Record>) = 31, будут или не будут?
← →
Defunct © (2005-06-02 10:03) [29]> jack128
> Хотя разговор довольно бессмысленный так как
ну для чего-то же все-таки есть ключевое слово packed. не может быть чтобы оно было просто бессмысленным.
← →
Игорь Шевченко © (2005-06-02 10:10) [30]jack128 © (02.06.05 09:57) [27]
> На самом деле если еще более абстрагироваться от конкретных
> платформ, то неупаковонный массив должен обеспечивать наиболее
> быстрый доступ к массиву
Безусловно.
Defunct © (02.06.05 10:03) [29]
> ну для чего-то же все-таки есть ключевое слово packed. не
> может быть чтобы оно было просто бессмысленным
Совершенно не бессмысленное. Во-первых, оно обеспечивает совместимость на уровне двоичного кода функций, написанных на разных языках, во-вторых, не все данные в жизни являются неупакованными, пример - заголовок исполняемого файла
← →
Defunct © (2005-06-02 10:29) [31]> Игорь Шевченко
> Во-первых, оно обеспечивает совместимость на уровне двоичного кода функций, написанных на разных языках
Напрашивается вопрос.
TRecord = record
F1..FN : Sometype
...
End;
TArray = packed array of TRecord
Будет ли TArray соответствовать вышесказанному?
← →
Ega23 © (2005-06-02 10:34) [32]2 Defunct © (02.06.05 10:29) [31]
Насколько я понял, имеется ввиду совместимость структуры на C и рекорда в Delphi. Ну, грубо говоря, как соглашение о вызове у функции.
Я packed использовал только для чтения хитрых бинарников и формировании данных для передачи по сети.
← →
Юрий Зотов © (2005-06-02 10:39) [33]> Defunct © (02.06.05 03:18) [18]
> скорее, не строго говоря, а в тех случаях когда
> тип_элемента - record и не объявлен с ключевым
> с ключевым словом packed либо не кратен 4.
Имеем динамический массив A с типом элемента byte. Есть поток MS класса TMemoryStream размером 12 байт, которые содержат:$01 $02 $03 $04 $05 $06 $07 $08 $09 $0A $0B $0C
Программа содержит операторы:
SetLength(A, MS.Size);
MS.Position := 0;
MS.ReadBuffer(A[0], Length(A) * SizeOf(byte));
Теперь вопрос (напоминаю, что директива packed имеет значение, если говорить именно строго - то есть, когда отсутствие этой директивы компилятором НЕ игнорируется, как оно и должно быть). Итак:
Как будет заполнен массив A в каждом из двух случаев:
- когда он упакован;
- когда он НЕ упакован.
Ответы:
- упакованный массив будет содержать в себе точную копию тела потока (поэлементно - см. выше).
- говоря строго, неупакованный массив будет содержать в себе следующее (буква M означает элемент массива, содержащий "мусор"):$01 $05 $09 М M M M M M M M M
(предполагается умалчиваемое выравнивание для 32-битных платформ - на границу двойного слова).
- говоря НЕ строго, неупакованный массив будет содержать в себе то же самое, что и упакованный.
Что же мы видим уже на этом элементарном примере?
1. Заполнение массива зависит от его упакованности именно говоря строго.
2. Никакие record"ы тут ни при чем - различие наблюдается даже на скалярных типах.
← →
Defunct © (2005-06-02 10:41) [34]packed = упакованый.
не обращаясь к справке, только по смыслу этого слова можно допустить, что независимо от компилятора каждое поле упакованой структуры будет размещено байт к байту с другими полями.
Вот собсно в этом вопрос, так ли это.
Достатоточно ли объявитьpacked array of TRecord
, чтобы неупакованые записи стали упаковаными в массиве?
← →
Defunct © (2005-06-02 10:44) [35]> Юрий Зотов
запостил [34] до того как появился Ваш ответ [33]. Но тем не менее если не трудно, можете ответить на [34]?
← →
evvcom © (2005-06-02 10:49) [36]
> Достатоточно ли объявить packed array of TRecord, чтобы
> неупакованые записи стали упаковаными в массиве?
Допустим SizeOf(TRecord)=6. Принимая во внимание сказанное (написанное) Юрием, packed array[0..1] будет состоять из 12 байт, а не упакованный из 16. Сами же TRecord как были не упакованными, так и останутся.
← →
Юрий Зотов © (2005-06-02 10:52) [37]> Defunct © (02.06.05 10:44) [35]
Точно не знаю, не проверял. Но можно проверить указанным в [33] способом.
← →
evvcom © (2005-06-02 10:54) [38]Кстати, в "потрепаться" затрагивался вопрос о нужности или не нужности понимания ассемблера. Вот он пример. Понимая асм программист может многое понять, не тратя гораздо большее время на поиски в интернете.
← →
Defunct © (2005-06-02 10:56) [39]evvcom © (02.06.05 10:49) [36]
Вполне логично, вечером проверю. Сейчас под рукой нет ни Delphi ни даже справки от него.
← →
evvcom © (2005-06-02 11:09) [40]Я уже проверил.
type
TRecord = record
c: Char;
w: WORD;
w1: WORD;
end;
const
ac1: TRecord = (c: "A"; w: $10; w1: $55);
ac2: TRecord = (c: "B"; w: $20; w1: $AA);
var
a1: array[0..1] of TRecord;
a2: packed array[0..1] of TRecord;
begin
a1[0] := ac1;
a1[1] := ac2;
a2[0] := ac1;
a2[1] := ac2;
end;
компилятор не делает разницы между packed array и не packed. Оба массива занимают по 12 байт:
41 00 10 00 55 00 42 00 20 00 AA 00
все hex
← →
evvcom © (2005-06-02 11:10) [41]+ А вот элементы массива по 6 байт, т.е. SizeOf(TRecord)
← →
Defunct © (2005-06-02 11:15) [42]> evvcom
ок, теперь все понятно. Вы были правы в [36].
> компилятор не делает разницы между packed array и не packed
А как же заставить компилятор чтобы массив был НЕ упакованым?
т.е. то про что говорил ЮЗ:
когда отсутствие этой директивы компилятором НЕ игнорируется
← →
Суслик © (2005-06-02 11:17) [43]
> А как же заставить компилятор чтобы массив был НЕ упакованым?
>
А оно вам надо?
← →
Суслик © (2005-06-02 11:20) [44]
> [42] Defunct © (02.06.05 11:15)
С трудом могу представить, когда это нужно. Как я говорил на это кладут сами разработчики borland. Не скажу где (т.к. не помню), но я вдиел в глубинах vcl игнорирование packed, хотя по месту это было необходимо.
Я сейчас постю и читаю группы на borland.com. Будет время спрошу про это.
← →
Anatoly Podgoretsky © (2005-06-02 11:24) [45]Defunct © (02.06.05 10:41) [34]
Достатоточно ли объявить packed array of TRecord, чтобы неупакованые записи стали упаковаными в массиве?
В данном контексте packed относится к самому массиву, а не элементам записи.
← →
Defunct © (2005-06-02 11:30) [46]> Суслик
Честно говоря - надо. Иначе бы и не спрашивал. Некоторые SSE команды работают только с данными, выровненными на границу QWORD иначе exception.
← →
evvcom © (2005-06-02 11:32) [47]
> А как же заставить компилятор чтобы массив был НЕ упакованым?
...
> Честно говоря - надо.
type
TRecord = record
c: Char;
w: WORD;
w1: WORD;
reserved: WORD;
end;
← →
Alx2 © (2005-06-02 11:33) [48]Defunct © (02.06.05 11:30) [46]
Кажется, есть аналоги для невыровненных данных.
← →
Defunct © (2005-06-02 11:39) [49]evvcom © (02.06.05 11:32) [47]
На данный момент именно так и поступаю.
Alx2 © (02.06.05 11:33) [48]
Но они работают медленнее почти в 2 раза
речь о
movdqa
и
movdqu
← →
Alx2 © (2005-06-02 12:03) [50]Defunct © (02.06.05 11:39) [49]
Увы. Компилятор Delphi (по крайней мере D6) не умеет делать требуемое выравнивание.
Чтобы это обойти, в критичных по скорости участках, я использую DLL, скомпилированные Intel C++ compiler. У него, кстати, кроме уже стандартных MMX, SSE, SSE2, SSE3 (в частности, для них он автоматом производит векторизацию и распараллеливание) есть оптимизация и под 64-битную архитектуру Itanium - пока еще большая редкость.
← →
begin...end © (2005-06-02 12:08) [51]> Defunct © (02.06.05 10:01) [28]
> Возможены случаи когда не будут.
Если утверждаете, то, вероятно, можете привести пример. Хотелось бы увидеть.
> SizeOf(<Record>) = 31, будут или не будут?
Будут.
> Defunct © (02.06.05 10:29) [31]
> TArray = packed array of TRecord
> Будет ли TArray соответствовать вышесказанному?
TArray будет упакованным, а его элементы будут неупакованными.
> Defunct © (02.06.05 10:41) [34]
> packed = упакованый.
> не обращаясь к справке, только по смыслу этого слова можно
> допустить, что независимо от компилятора каждое поле упакованой
> структуры будет размещено байт к байту с другими полями.
> Вот собсно в этом вопрос, так ли это.
Если запись объявлена с packed, то поля записи будут прижаты.
Если массив объявлен с packed, то элементы массива будут прижаты.
Если массив объявлен без packed, то элементы всё равно будут прижаты.
> Достатоточно ли объявить packed array of TRecord, чтобы
> неупакованые записи стали упаковаными в массиве?
Конечно, нет. Потому что в данном случае packed относится к размещению элементов массива, а не к размещению полей в этих элементах.
А если бы при таком объявлении записи упаковывались, как тогда выглядело бы присваивание значения элементу такого массива? По-Вашему, компилятор будет брать каждое поле из присваиваемой записи и помещать его в соответствующее поле упакованного элемента массива, вместо того чтобы скопировать целиком неупакованную запись?
По-моему, всё логично и понятно. Кроме того, что массивы всегда (независимо от наличия packed) упаковываются.
← →
TUser © (2005-06-02 12:08) [52]> > А как же заставить компилятор чтобы массив был НЕ упакованым?
Можно обявить array of TCoolRecord, где в TCoolRecord забить нужное кол-во бополнительных полей соотвествующего размера, например
TCoolRecord =
record
B1, B2: boolean; // 2 байта
C1, С2, С3: shortint; // 3 байта
Zero: array [0..2] of byte; // not used
end;
Интересно, не с этим ли связано появление reserved агрументов в некоторых API функциях?)
← →
Defunct © (2005-06-02 12:18) [53]> begin...end
Все было просто отлично, доходчиво и логично, до вот этого:
По-Вашему, компилятор будет брать каждое поле из присваиваемой записи и помещать его в соответствующее поле упакованного элемента массива, вместо того чтобы скопировать целиком неупакованную запись?
Обязательно надо было ложку дёгтя в бочку мёда засунуть?
Было бы "по-моему" еще неизвестно как сделал бы.
> не с этим ли связано появление reserved агрументов в некоторых API функциях
Вполне возможно.
← →
begin...end © (2005-06-02 12:23) [54]> Defunct © (02.06.05 12:18) [53]
> Обязательно надо было ложку дёгтя в бочку мёда засунуть?
> Было бы "по-моему" еще неизвестно как сделал бы.
Я просто не понял, как Вы себе представляете действия компилятора в данном случае. Потому и спросил.
← →
evvcom © (2005-06-02 12:39) [55]Кстати, переделал код:
type
TRecord = record
dw: DWORD;
c: Char;
end;
const
ac1: TRecord = (dw: $11111111; c: "A");
ac2: TRecord = (dw: $22222222; c: "B");
var
a1: array[0..1] of TRecord;
a2: packed array[0..1] of TRecord;
begin
a1[0] := ac1;
a1[1] := ac2;
a2[0] := ac1;
a2[1] := ac2;
end;
Компилятор между этими массивами опять не видит никакой разницы, но результат теперь такой:
11 11 11 11 41 00 00 00
22 22 22 22 42 00 00 00
Проверил SizeOf(TRecord), теперь он =8, хотя в предыдущем был =6. Вот этим 8 и 6 я что-то объяснения найти не могу пока.
← →
Sapersky (2005-06-02 15:15) [56]Логика выравнивания полей неупакованных записей довольно хитрая, это не просто "расставить поля по адресам кратным 4".
См. хелп: Object Pascal Reference \ Memory management \ Record types
Массивы, видимо, выравниваются по такому же принципу.
Страницы: 1 2 вся ветка
Форум: "Основная";
Текущий архив: 2005.06.29;
Скачать: [xml.tar.bz2];
Память: 0.61 MB
Время: 0.045 c