Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Любопытный record

6
30 июня 2010 года
George
4.1K / / 05.01.2007
Увидел такую структуру:
[highlight=delphi]
TMD5Digest = record
case Integer of
0: (A, B, C, D: LongInt);
1: (v: array[0..15] of Byte);
end;[/highlight]
И что-то совсем ее не понял. Может объяснит кто? :)
5
30 июня 2010 года
hardcase
4.5K / / 09.08.2005
Это вариантная запись. Аналог union'а из C.
Оффсет расположения в памяти элемента A и v одинаков. Таким образом, изменяя значения вектора v изменяются значения именованых элементов (и наоборот, меняем именованые элементы - меняется вектор).
И небольшое замечание - я бы к объявлению записи добавил модификатор packed, иначе можно огрести проблемы при изменении параметра выравнивания.
416
30 июня 2010 года
MaitreDesir
380 / / 02.01.2008
От себя добавлю, что, очевидно, в данной ситуации запись используется для побайтного доступа к LongInt'ам A,B,C,D. Кроме этого можно использовать такой вид:

 
Код:
TContentType=(ctAsLongInt,ctAsByteArray);
TMD5Digest = record
    case ContentType:TContentType of
      ctAsLongInt: (A, B, C, D: LongInt);
      ctAsByteArray: (v: array[0..15] of Byte);
  end;


В этом случае запись можно использовать наподобие переменных типа Variant, однако хранить как простые данные, так и объекты и т.п., при этом экономя память. Доступ к нужным данным при этом можно разграничивать посредством расшифровки значений поля ContentType.
5
01 июля 2010 года
hardcase
4.5K / / 09.08.2005
Цитата: MaitreDesir
В этом случае запись можно использовать наподобие переменных типа Variant, однако хранить как простые данные, так и объекты и т.п., при этом экономя память

А где тут экономия памяти?

6
01 июля 2010 года
George
4.1K / / 05.01.2007
Цитата: hardcase
А где тут экономия памяти?


У меня часто возникает вопрос, нужна ли вообще подобная экономия памяти в подобных мелочах? Понятно, что огульно расшвыриваться ею не стоит, но и сходить с ума, оптимизируя затраты неохота. Впрочем это, видимо, ситуативно, ведь может быть явление, когда есть структура, в которой можно сэкономить память, а структур таких используется в рантайме великое множество.
Ну это я так, вслух подумал.

303
01 июля 2010 года
makbeth
1.0K / / 25.11.2004
Жоржи, ведь при присваивании переменных с типом структура происходит полное копирование. Так что профит от "экономии" здесь очевиден.
6
01 июля 2010 года
George
4.1K / / 05.01.2007
Цитата: makbeth
Жоржи, ведь при присваивании переменных с типом структура происходит полное копирование. Так что профит от "экономии" здесь очевиден.


Но если ты это делаешь один раз, то разве есть смысл?

303
01 июля 2010 года
makbeth
1.0K / / 25.11.2004
Цитата: George
Но если ты это делаешь один раз, то разве есть смысл?


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

326
05 августа 2010 года
sadovoya
757 / / 19.11.2005
Разумный баланс между надежностью кода и его эффективностью - лучший стиль программирования, как мне кажется. В зависимости от задачи весовые коэффициенты разумеется меняются в этом балансе. А на счет "хитрой" записи - тут справедливо заметили, что о выравнивании памяти надо помнить. Пакованый вариант мне тоже больше нравится.
253
05 августа 2010 года
Proger_XP
1.5K / / 07.08.2004
Я case в record'ах за последние несколько лет использовал всего раза два. Они нужны, когда хочется использовать одно объявление записи вмсесто нескольких - то есть совместить их все в одной (естесственно, предполагается, что поля не будут перекрываться).
Но оп-моему такая конструкция не наглядная и с ней надо быть осторожным.

Экономия памяти и packed в масштабе нескольких байт на запись сегодня даже на нетбуках не актуальна, а вот обычные unpacked record'ы могут основательно повысить скорость, ибо процу проще оперировать над указателями, кратными 32 битам. С другой стороны, на сегодняшних компах и бонус в скорости может быть не больше, чем был бы бонус в памяти от packed record'ов...
Я лично использую packed только для тех типов, которые пишутся в файл.

Цитата: MaitreDesir

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


Вообще говоря, TVarRec именно так и определён:

 
Код:
TVarRec = record
    case Byte of
      vtInteger:    (VInteger: Integer; VType: Byte);
      vtBoolean:    (VBoolean: Boolean);
      vtChar:       (VChar: Char);
      vtExtended:   (VExtended: PExtended);
      // и т.д.


Это по-моему один из очень немногих случаев, когда использование case в record весьма оправдано.

Цитата: hardcase
А где тут экономия памяти?


Вместо 4*4 байт для 4х Integer + 16 байт для array of Byte = 32, используется всего 16 и под то, и под другое.
Просто MaitreDesir по-моему привёл неудачный пример, TVarRec нагляднее.

5
05 августа 2010 года
hardcase
4.5K / / 09.08.2005
Цитата: Proger_XP

Вместо 4*4 байт для 4х Integer + 16 байт для array of Byte = 32, используется всего 16 и под то, и под другое.

Такие конструкции нужны для реинтерпретации памяти, например, для отображения массива на набор именованных элементов. А для экономии памяти нужно алгоритмы правильные выбирать, а не структуры данных нарушающие принцип инкапсуляции - это я имел в виду а теперь выразил словами.

253
05 августа 2010 года
Proger_XP
1.5K / / 07.08.2004
Согласен.

Цитата: hardcase
А для экономии памяти нужно алгоритмы правильные выбирать, а не структуры данных нарушающие принцип инкапсуляции.


Это тоже верно, тем более, что экономить память на таких вещах сродни предоптимизации.

10
05 августа 2010 года
Freeman
3.2K / / 06.03.2004
Цитата: hardcase
для реинтерпретации памяти


В советское время это называли привидением типа.

5
05 августа 2010 года
hardcase
4.5K / / 09.08.2005
Цитата: Freeman
В советское время это называли привидением типа.

Это не приведение типа, но реинтерпретация памяти, так как мы не производим действий ни для проверки возможности преобразования объекта одного типа в другой, ни действий для этого.

10
05 августа 2010 года
Freeman
3.2K / / 06.03.2004
Цитата: hardcase
Это не приведение типа


Код:
type

[...]

{ Type conversion records }

  WordRec = packed record
    case Integer of
      0: (Lo, Hi: Byte);
      1: (Bytes: array [0..1] of Byte);
  end;

  LongRec = packed record

[...]

  Int64Rec = packed record

Взято из SysUtils.pas, в тему ТС.
5
05 августа 2010 года
hardcase
4.5K / / 09.08.2005
Цитата: Freeman
Код:
type

[...]

{ Type conversion records }

  WordRec = packed record
    case Integer of
      0: (Lo, Hi: Byte);
      1: (Bytes: array [0..1] of Byte);
  end;

  LongRec = packed record

[...]

  Int64Rec = packed record

Взято из SysUtils.pas, в тему ТС.




Будет ли следующее объявление служить приведением типа между Integer и Real?

 
Код:
type T = packed record
  case Integer of
    0: (X, Y : Integer);
    1: (Z : real);

end;

А также TButton и string?
 
Код:
type T = packed record
  case Integer of
    0: (X : TButton);
    1: (Z : string);

end;




З.Ы. я рассуждаю с позиций развитых систем типов C++ и .NET
10
05 августа 2010 года
Freeman
3.2K / / 06.03.2004
Цитата: hardcase
Будет ли следующее объявление служить приведением типа между Integer и Real?


А что требуется получить? Если нужно показать низкоуровневое представление вещественных типов сопроцессором - очень даже, только в 16-ричном виде вывести.

А TButton (TObject) и string часто приводят к Integer и наоборот. Тема ж не про .NET. В советское время .NET-а не было. :D

5
05 августа 2010 года
hardcase
4.5K / / 09.08.2005
Цитата: Freeman
А что требуется получить? Если нужно показать низкоуровневое представление вещественных типов сопроцессором - очень даже, только в 16-ричном виде вывести.

А TButton (TObject) и string часто приводят к Integer и наоборот. Тема ж не про .NET. В советское время .NET-а не было. :D


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

И да, причем тут советское время?

14
06 августа 2010 года
Phodopus
3.3K / / 19.06.2008
Преобразование типа и приведение типа все же разные по смыслу вещи. type conversion - преобразование, type cast - приведение. В данном случае (sysutils.pas) имеется ввиду преобразование/реинтерпретация типа, подобно reinterpret_cast<>()
30K
18 августа 2010 года
Mawrat
5 / / 13.07.2007
Цитата: hardcase
Будет ли следующее объявление служить приведением типа между Integer и Real?
 
Код:
type T = packed record
  case Integer of
    0: (X, Y : Integer);
    1: (Z : real);
end;


В Delphi 7 Real является псевдонимом типа Double:

 
Код:
type Real = type Double;

Вместо него лучше пользоваться 10 байтным типом Extended - к которому по умолчанию приводятся значения вещественных выражений.
Что касается форматов представления целых и вещественных чисел в памяти - они совершенно различные.
Целые представляются таким образом, что младшие байты числа расположены в ячейках с младшими адресами, а старшие - в старших, соответственно. Отрицательные целые числа представляются в дополнительном коде.
Вещественные - представлены в памяти в направлении от старших адресов - к младшим: один знаковый разряд, группа разрядов экспоненты, группа разрядов нормализованной мантиссы (в десятичном виде значение равно от 0 включительно до 2 с исключением).
Представление вещественных чисел можно поизучать на онлайн калькуляторах IEEE.
Цитата: hardcase

А также TButton и string?
 
Код:
type T = packed record
  case Integer of
    0: (X : TButton);
    1: (Z : string);
end;


Вместо этого кода удобнее написать так:

 
Код:
Str1 := String( Pointer(Button1) );
//и:
Button1 := TButton( Pointer(Str1) );

Смысла в этом нет, если в проге не придумано что-то такое неизвестно зачем замудрёное. :)
Строка тип String - это указатель на ячейку (байт) в памяти, начиная с которого расположен массив символов строки. Последним символом является терминальный ноль #0 - распложен в позиции:
Str1[Length(Str1) + 1)
Кроме этого строка содержит метаданные - это сведения о размере выделенной памяти, количестве ссылок на строку, длина строки (без учёта терминального нуля). Эти метаданные расположены в младших адресах перед массивом символов строки:
Код:
var
  P, PSize, PRefCnt, PLen : ^Integer;
  i : Integer;
  Str1 : String;
begin
  SetLength(Str1, 20);
  for i := 1 to Length(Str1) do Str1 := '1';
  P := Pointer(Str1);
  PSize := Pointer( Integer(P) - 12 );
  PRefCnt := Pointer( Integer(P) - 8 );
  PLen := Pointer( Integer(P) - 4 );
  ShowMessage(
    'Строка: "' + Str1 + '"' + #10
    + 'Общий объём памяти (байт), выделенной для строки = ' + IntToStr(PSize^) + #10
    + 'Длина (количество символов) без учёта терм. нуля = ' + IntToStr(PLen^) + #10
    + 'Количество ссылок на строку = ' + IntToStr(PRefCnt^)
  );
end;

В Delphi 7 объём памяти для строки равен:
 
Код:
var
  Str1 : String;
  MemSize, AnyAdd : Integer;
begin
...
  MemSize := 3 * SizeOf(Integer) + Length(Str1) * SizeOf(Char) + 1 * SizeOf(Char) + AnyAdd;

AnyAdd - это некоторая величина, выбираемая менеджером памяти Delphi. Эти дополнительные байты видимо расположены в старших адресах относительно терминального нуля. Я не встречал в инете какой-либо инфы об их назначении. Чем длиннее строка, тем значение AnyAdd может быть большим.
Что касается Button1 : TButton и вообще любого экземпляра класса (объекта) - это указатель на ячейку памяти, начиная с которой расположены сами данные экземпляра (объекта).
5
18 августа 2010 года
hardcase
4.5K / / 09.08.2005
Цитата: Mawrat
...


Я рад что вы хорошо разбираетесь в Delphi.
Правда вопросы мои были не от того, что я не знаю предмета, а для того, чтобы показать разницу в интерпретации понятия "приведение типа". С позиций одних языков - это переинтерпретация памяти, с позиций же других языков - это честное типобезопасное конвертирование значений.

14
18 августа 2010 года
Phodopus
3.3K / / 19.06.2008
Цитата: Mawrat
В Delphi 7 Real является псевдонимом типа Double:
...


:D
вообще вопрос был задан какбэ риторический, и если уж требовал на него ответа то достаточно было "да" или "нет".
ПыСы. Харкейс, опередил! :)

30K
23 августа 2010 года
Mawrat
5 / / 13.07.2007
Цитата: hardcase
Я рад что вы хорошо разбираетесь в Delphi.
Правда вопросы мои были не от того, что я не знаю предмета, а для того, чтобы показать разницу в интерпретации понятия "приведение типа". ...


Сейчас перечитал посты - да я в контекст не вник - прямолинейно по вопросам ответил. :D

Цитата: Phodopus
:D
вообще вопрос был задан какбэ риторический, и если уж требовал на него ответа то достаточно было "да" или "нет".
ПыСы. Харкейс, опередил! :)


Понятно. :)

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог