Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  17:55[Войти] | [Зарегистрироваться]
Ответ на вопрос № 83749

08-10-2020 01:30
Здравствуйте.

Задан тип структуры
Type  TRec = record
        f1: Type1;
        .........
        fn: TypeN;   
      end;

статическая переменная и динамический массив с этой структурой
var
vr: TRec;
DA : array of TRec;

Так вот, формат структуры после компилирования (расположение и  размер полей) будут разные у переменной и динамического массива.
В динамическом массиве компилятор оптимизирует расположение полей, а в переменной - нет.
Но это полностью нарушает работу программы, т.к. в ней передаются адреса (ссылки) на переменные с этим типом и нарушение полей структуры всё портит.
Вопрос, есть ли какая-нибудь директива компилятора, которая пресекает подобную его самодеятельность? (т.е., чтобы размер полей и их расположение  не менялись).

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице.
Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.

21-10-2020 03:07
В type перед ключевым словом record поставьте packed, тогда переменные в типе будут размещаться как они есть без выравнивания:

type
  TRec=packed record
    ..
  end;


10-10-2020 00:39 | Комментарий к предыдущим ответам
Проверил выравнивание памяти на Lazarus, но оно работает вполне предсказуемо, как и ожидалось:

program SizeofTest;

{$A-}

Uses
  SysUtils;

Type
  PPony=^TPony;
  TPony=record
    Twilight:byte;
    Rarity:word;
    Applejack:string;
  end;
  TPoniez=array of TPony;

procedure PrintPony(Pony:PPony);
begin
  Writeln(
    'Twilight=',inttohex(Pony^.Twilight,2),
    ' Rarity=',inttohex(Pony^.Rarity,4),
    ' Applejack=',inttohex(IntPtr(@Pony^.Applejack[1]),8)
  );
end;

procedure PrintInternal(const V;Size:word);
var
  P:PByte;
begin
  P:=@V;
  while Size>0 do begin
    Write(inttohex(P^,2),' ');
    Inc(P);
    Dec(Size);
  end;
  Writeln;
end;

var
  P:TPony;
  Ps:TPoniez;
  I:integer;
begin
  P.Twilight:=$AA;
  P.Rarity:=$1234;
  P.Applejack:='Applez';
  SetLength(Ps,4);
  For I:=0 to 3 do begin
    Ps[I].Twilight:=I;
    Ps[I].Rarity:=2*I;
    Ps[I].Applejack:=inttostr(I*4);
  end;
  PrintPony(@P);
  PrintInternal(P,sizeof(P));
  For I:=0 to 3 do begin
    PrintPony(@Ps[I]);
    PrintInternal(Ps[I],sizeof(Ps[I]));
  end;
  Readln;
end.


Результат для по умолчанию:
Twilight=AA Rarity=1234 Applejack=00416034
AA 00 34 12 34 60 41 00
Twilight=00 Rarity=0000 Applejack=0006079C
00 00 00 00 9C 07 06 00
Twilight=01 Rarity=0002 Applejack=000607BC
01 00 02 00 BC 07 06 00
Twilight=02 Rarity=0004 Applejack=000607DC
02 00 04 00 DC 07 06 00
Twilight=03 Rarity=0006 Applejack=000607FC
03 00 06 00 FC 07 06 00

Результат с директивой $A- (нет выравнивания):
Twilight=AA Rarity=1234 Applejack=00416034
AA 34 12 34 60 41 00
Twilight=00 Rarity=0000 Applejack=0006079C
00 00 00 9C 07 06 00
Twilight=01 Rarity=0002 Applejack=000607BC
01 02 00 BC 07 06 00
Twilight=02 Rarity=0004 Applejack=000607DC
02 04 00 DC 07 06 00
Twilight=03 Rarity=0006 Applejack=000607FC
03 06 00 FC 07 06 00

Вывод: структура записи в памяти не зависит от того, находится ли она в массиве, или просто валяется где-то как отдельная переменная, тогда как даже внутри одного коноплятора, но при разных настройках оного, выравнивание полей может меняться, чего уж говорить о случае, где используются разные конопляторы. Впрочем, данный вывод естественным образом вытекает из документации и никакой ценности из себя не представляет.

09-10-2020 09:16 | Комментарий к предыдущим ответам
Поля в записи равняются чётко, и к гадалке не ходи)

Вот версия с контролем адресов:

program AlignTest;

{$APPTYPE CONSOLE}
{$A4}

type
  TComplex = record
    re: Extended;
    im: Extended;
  end;

var z: TComplex;

DCX: array of TComplex;

procedure test(const z: TComplex);
begin
  Writeln(SizeOf(z):4, SizeOf(z.re):4, SizeOf(z.im):4, integer(@z):10, integer(@z.re):10, integer(@z.im):10);
end;

begin
  test(z);
  test(dcx[0]);
  test(dcx[1]);
end.


Вывод (граница 4 байта):
  24  10  10  4216412  4216412  4216424
  24  10  10        0        0        12
  24  10  10        24        24        36

Компилировалось на D7

09-10-2020 08:11 | Комментарий к предыдущим ответам
Я тоже погонял тестовую программу (правда, на D7). И тоже для SizeOf получил либо 20, либо 24. Но когда заглянул внутрь (дамп памяти посмотрел), такое ощущение, что даже при выравнивании на 4 байта, поля в записи идут плотно. Дальше рыть не стал, так как floating-point типы в памяти читаю плохо, а детально разбираться лениво.

Есть хорошее правило. Если работаешь с record честно (предусмотренными штатным возможностями языка), то глубоко плевать, как там в памяти это хранится: компилятор знает сам и сделает правильно. Если же предполагается низкоуровневая работа (использование record как буфер с некоторой структурой), то используй packed record со строго определенным и документированным расположением полей.

09-10-2020 02:47
Я совершенно согласен с господином Geo.

Выравнивание полей простых типов в записях (и объектах) по-умолчанию подчиняется правилу:
типы размером 1 байт (byte, char) - на границу байта
типы размером 2 байта (word, widechar) - на границу слова (адрес кратен 2)
типы размером 4 байта (integer, float) - на границу двойного слова (адрес кратен 4)
типы размером 8 байт (int64, double) - на границу 64 бит (адрес кратен 8)
тип extended - на границу 128 бит (адрес кратен 16)

Выравнивание можно отменить, если вместо record написать packed record, или ввести директиву {$A-} или {$A1}.
Тогда все поля будут выравниваться на границу байта, т.е. упакованы плотно.

Директива с явным указанием границы задаёт максимальную границу.

Любые переменные и массивы от одного объявленного типа записи будут иметь идентичную структуру в памяти.
Поэтому я спорю с этим вашим утверждением:
Так вот, формат структуры после компилирования (расположение и  размер полей) будут разные у переменной и динамического массива.
В динамическом массиве компилятор оптимизирует расположение полей, а в переменной - нет.


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

program AlignTest;

{$APPTYPE CONSOLE}

type
  TComplex = record
    re: Extended;
    im: Extended;
  end;

var z: TComplex;

DCX: array of TComplex;

begin
  Writeln(SizeOf(z):4, SizeOf(z.re):4, SizeOf(z.im):4);
  Writeln(SizeOf(dcx[0]):4, SizeOf(dcx[0].re):4, SizeOf(dcx[0].im):4);
  Writeln(Integer(@dcx[0]):4,Integer(@dcx[1]):4);
end.

Опции компилятора по-умолчанию. Вывод программы такой:
  32  10  10
  32  10  10
  0  32

Опция {$A1} (или packed record):
  20  10  10
  20  10  10
  0  20

Опция {$A2} - то же самое, и понятно, почему.

Опция {$A4}:
  24  10  10
  24  10  10
  0  24

Опция {$A8} (по-умолчанию):
  32  10  10
  32  10  10
  0  32

Опция {$A16} - то же, что и {$A8} (для данного случая).

Поэтому, уважаемый автор, ошибка у вас не в компиляторе, а совсем в другом месте.
Не нужно делать предположения о размере структур и элементов массива. Нужно использоваать SizeOf()

ЗЫ. В Си для достижения плотной упаковки используют директиву #pragma pack(1). А по-умолчанию - такие же правила как и в Паскале.

08-10-2020 05:22
Есть такая вещь, как выравнивание адресов данных на адреса кратные... э-э-э,,, как бы это сказать... кратные количеству байт в разрядности процессора :-)
Для 16-разрядных системы выравнивание производилось по четным адресам, для 32-разрядных — на адреса, кратные 4. Предполагаю, что для 64-разрядных систем выравнивание выполняется на адреса, кратные 8. В этом случае доступ к данным происходит чуть быстрее.

Если вы не хотите такой оптимизации, используйте packed record. В этом случае выравнивание для оптмизиции выполняться не будет, а поля буду идти подряд плотно.

08-10-2020 04:39
:) Значит вы не сталкивались с этой проблемой. Многие языки этим грешат. Я на форумах встречал такие обсуждения. К тому же в разных языках одна и та же структура может компилироваться по разному.
Простой пример в Дельфи
Type TComplex = record
                re: Extended;
                im: Extended;
                end;
при статическом объявлении
z: TComplex;
  размеры полей re,im будут 12 байтов. (в GCC эти поля имеют размер уже 16 байтов)

Но при задании динамического массива от этой структуры
DCX: array of TComplex;
  размеры каждого поля становятся 10 байт. (как и должно быть в типе Extended).

Получается полная несовместимость.

08-10-2020 01:39 | Вопрос к автору: запрос дополнительной информации
Уважаемый, вы какую-то ересь пишете)
Единожды объявленная структура будет везде одинакова, с точностью до байта.
Приведите доказательства.

Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Однажды, в студеную зимнюю пору я из лесу вышел, был сильный ЧТО?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования