Тип Currency. Подскажите, в чём прикол?

Форум для изучающих FPC и их учителей.

Модератор: Модераторы

Тип Currency. Подскажите, в чём прикол?

Сообщение Putnick » 10.10.2012 09:06:25

Здравствуйте!
Возникло непонимание. Есть такой код:
Код: Выделить всё
program prog1;
type
  PRaw=^Traw;
  TRaw=array [0..5] of Currency;
var
  a,b,c:Currency;
  tmp:PRaw;
  i:integer;
begin
  tmp:=@a;
  for i:=0 to 5 do
  tmp^[i]:=i;
  WriteLn(a,' ',b,' ',c);
  ReadLn
end.

При компиляции в Лазарусе 1.0 на выходе имеем:
Код: Выделить всё
a=0;
b=2;
c=4;

Хотя, как мне казалось, должно было быть:
Код: Выделить всё
a=0;
b=1;
c=2;

или даже ошибка доступа - ведь память за переменной С не выделена.
Подскажите, в чём я ошибаюсь?
Putnick
новенький
 
Сообщения: 62
Зарегистрирован: 18.03.2009 13:02:56

Re: Тип Currency. Подскажите, в чём прикол?

Сообщение .wOvAN » 10.10.2012 09:52:13

в b и с произвольные значения поскольку им ничего не присваивается.
.wOvAN
постоялец
 
Сообщения: 118
Зарегистрирован: 16.04.2010 06:36:12

Re: Тип Currency. Подскажите, в чём прикол?

Сообщение SSerge » 10.10.2012 10:02:07

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

Реальный пример, как делать вообще нельзя. Никогда. Ни при каких обстоятельствах.

Putnick, изучи какой нибудь язык типа явы, у которого нет указателей и привыкни работать с переменными как подобает в языках высокого уровня, а не как поступали в ассемблере ZX Spectrum.
SSerge
энтузиаст
 
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Re: Тип Currency. Подскажите, в чём прикол?

Сообщение Putnick » 10.10.2012 13:15:22

SSerge писал(а):Бгг.... Как нравится мне смотреть, как люди сами придумывают себе проблемы.

Ну, вообще-то, как по мне, не самый плохой способ понять как что-то работает. Тем более, что я как раз хотел избежать проблемы - если переменные обрабатываются по одинаковому алгоритму (скажем, проверка правильности ввода в каком-нибудь StringGrid'е), то почему бы не обрабатывать их в цикле?
SSerge писал(а):Автор кода из каких то собственных умозаключений вдруг решил, что все переменные будут размещены последовательно и он их здорово отмапит на массив; при этом забывает о выравнивании и прочем.

То, что переменные будут размещены последовательно мне казалось КРАЙНЕ логичным. Да, собственно, пример это подтверждает (с оговоркой). А вот на счёт "выравнивания и прочего" - если не трудно, по-подробнее? Мне, по старой памяти, казалось, что выравнивание бывает на 8/16/32 бита, а тут - на 128 получается...
SSerge писал(а):А потом еще и присваивает области памяти, даже по его же коду распределенной для трех элементов, пять элементов размапленного массива. Даже если массив действительно мапится, то два то элемента за пределами выделенной компилятором области.

Ну, об этом я, как бы, писал:
или даже ошибка доступа - ведь память за переменной С не выделена.

В остальном, уважаемый SSerge, благодарю Вас за ответ. И буду в двойне благодарен, если просветите на счёт "выравнивания и прочего".

С уважением, Алексей.

Добавлено спустя 14 минут 42 секунды:
.wOvAN писал(а):в b и с произвольные значения поскольку им ничего не присваивается.

Ага, строго произвольные 2 и 4 :D
Putnick
новенький
 
Сообщения: 62
Зарегистрирован: 18.03.2009 13:02:56

Re: Тип Currency. Подскажите, в чём прикол?

Сообщение SSerge » 10.10.2012 13:45:34

Там может быть и выравнивание не причем;
интересу ради, сравните значение tpm с адресом переменной "а" после того, как надругались над четвертым и пятым элементами массивов; даже если все линейно, то вы присвоением то часть указателя переписали :)

В любом случае, явные ошибки алгоритмики налицо; если сильно хочется посмотреть, что именно происходит, что ж не поставить отладчиком точку останова и взглянуть на код дизассемблера?
SSerge
энтузиаст
 
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Re: Тип Currency. Подскажите, в чём прикол?

Сообщение Vapaamies » 10.10.2012 20:25:51

Putnick писал(а):А вот на счёт "выравнивания и прочего" - если не трудно, по-подробнее? Мне, по старой памяти, казалось, что выравнивание бывает на 8/16/32 бита, а тут - на 128 получается...

Начиная с процессоров Pentium IV (?), оптимальным стало считаться выравнивание на границу 8 байт. К тому времени размеры установленного ОЗУ на клиентских машинах подросли, и программисты стали меньше считаться с расходами. Плюс, выравнивание на 8 байт полезно для всяких MMX/SSE, которые, бывает, и пользуются, -- в FastMM и всяких FastCode.

Короче, в Delphi 5, если мне не изменяет память, {$A+} выравнивал на 4 байта, а в Delphi 6 -- уже на 8.

Кроме того, при наличии достаточного числа регистров значения могут быть размещены в них, а не в памяти. На платформе x64 уже много регистров, чтобы это считалось справедливым намного чаще, чем для куцей регистровой модели 32-битного x86. Не уверен, правда, что тип Currency размещается в регистрах... Тут уже надо доку конкретно FPC смотреть.

Как бы то ни было, согласен с SSerge: так делать никогда нельзя!
Аватара пользователя
Vapaamies
постоялец
 
Сообщения: 292
Зарегистрирован: 24.07.2012 22:37:59
Откуда: Санкт-Петербург

Re: Тип Currency. Подскажите, в чём прикол?

Сообщение zub » 10.10.2012 22:26:42

>>То, что переменные будут размещены последовательно мне казалось КРАЙНЕ логичным
да логично и пока вроде так и есть, но при очередном обновлении компилятора всё может поменяться. расположение локальных переменных в стеке задом наперед объявлению или в алфавитном порядке ничуть не менее логично. Упование на такие логичности сулит разгоебание непонятных багов с каждой новой версией компилятора. Например ссылка у вас есть только на переменню а (tmp:=@a;) и то что b и c лежат в памяти а не в регистрах - везение и игра опций оптимизации компилятора и целевой платформы. Компилятор не понимает такой способ изменения переменных (b,c) и может сделать c ними всё что душе угодно, например вообще их выкинуть как неиспользуемые (пока есть WriteLn(a,' ',b,' ',c) не выкинет)

>>по старой памяти, казалось, что выравнивание бывает на 8/16/32 бита, а тут - на 128 получается...
В данном случае выравнивание 16, т.е. a это [0], b это [2] и c это [4]

>>так делать никогда нельзя!
Так делать нельзя, но указатели ипользовать можно и иногда нужно (хотел привести хотел привести пример где без указателей никак, но чтото не сиог придумать :D )
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Тип Currency. Подскажите, в чём прикол?

Сообщение Putnick » 10.10.2012 22:38:14

Vapaamies писал(а):Кроме того, при наличии достаточного числа регистров значения могут быть размещены в них, а не в памяти. На платформе x64 уже много регистров, чтобы это считалось справедливым намного чаще, чем для куцей регистровой модели 32-битного x86. Не уверен, правда, что тип Currency размещается в регистрах... Тут уже надо доку конкретно FPC смотреть.

Как бы то ни было, согласен с SSerge: так делать никогда нельзя!

Благодарю за разъяснения, о регистрах/ММХах не подумал.
Хотя, забавно - вот такое:
Код: Выделить всё
program test;
type
  tst=record
   a,b,c:currency
  end;
  PRaw=^TRaw;
  TRaw=array [0..2] of currency;
var
  t:tst;
  tmp:PRaw;
  i:integer;
begin
  tmp:=@t.a;
  for i:=0 to 2 do
    tmp^[i]:=i;
  writeLn(t.a,' ',t.b,' ',t.c);
  Readln;
end.

работает.
Впрочем, Zub - отдельное ему спасибо - всё очень вдумчиво и подробно разъяснил, на счёт везения и зависимости от особенностей компилятора и платформы, которые могут и поменяться.
Putnick
новенький
 
Сообщения: 62
Зарегистрирован: 18.03.2009 13:02:56

Re: Тип Currency. Подскажите, в чём прикол?

Сообщение zub » 10.10.2012 22:55:46

>>В данном случае выравнивание 16, т.е. a это [0], b это [2] и c это [4]
Тут я погоречился походу, в массиве свое выравнивание, в стеке свое. они пересеклись на 2 и 4. т.е. выравнивание в стеке больше в 2 раза выравнивания в массиве?
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Тип Currency. Подскажите, в чём прикол?

Сообщение Vapaamies » 11.10.2012 00:06:39

Putnick писал(а):
Код: Выделить всё
  tst=record
   a,b,c:currency
  end;
  PRaw=^TRaw;
  TRaw=array [0..2] of currency;


Не уверен, что сработает в Delphi. Для гарантии в Delphi я бы объявил tst как packed record.

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

Продолжая разговор о способах размещения, могу добавить, что есть такая штука, как оптимизация размещения в стеке согласно фактическому использованию. Delphi об этом сообщает подсказкой "xxx never used" -- когда переменная полностью выкидывается. А если не выкидывается, компилятор использует хитрый алгоритм, деля код на неявные блоки -- от первого использования переменной до последнего, и каждая переменная существует только в рамках этого блока -- прямо как в Си. Сообщение отладчика "xxx inaccessible here due to optimization" -- как раз про это. В длинной процедуре часть локальных переменных может быть размещена поверх других, уже вышедших из области видимости. Это внутренняя кухня компилятора, и предсказать ее никак невозможно.

Добавлено спустя 8 минут 15 секунд:
zub писал(а):Тут я погоречился походу, в массиве свое выравнивание, в стеке свое.

В массивах нет выравнивания, по крайней мере в Delphi.
Аватара пользователя
Vapaamies
постоялец
 
Сообщения: 292
Зарегистрирован: 24.07.2012 22:37:59
Откуда: Санкт-Петербург

Re: Тип Currency. Подскажите, в чём прикол?

Сообщение SSerge » 12.10.2012 06:31:28

Putnick писал(а):Хотя, забавно - вот такое:

Код: Выделить всё
program test;
type
tst=record
a,b,c:currency
end;
PRaw=^TRaw;
TRaw=array [0..2] of currency;
var
t:tst;
tmp:PRaw;
i:integer;
begin
tmp:=@t.a;
for i:=0 to 2 do
tmp^[i]:=i;
writeLn(t.a,' ',t.b,' ',t.c);
Readln;
end.


работает.



А чего забавного то; выхода размапленного массива за пределы выделенной для данных памяти нет;
Если в первом примере ограничитесь массивом из трех элементов, то можете получить ту же картину; хотя, повторюсь, подход принципиально неправильный :D
SSerge
энтузиаст
 
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Re: Тип Currency. Подскажите, в чём прикол?

Сообщение Putnick » 12.10.2012 10:02:11

SSerge писал(а):А чего забавного то; выхода размапленного массива за пределы выделенной для данных памяти нет;
Если в первом примере ограничитесь массивом из трех элементов, то можете получить ту же картину; хотя, повторюсь, подход принципиально неправильный :D

Уточняю - даёт корректный результат - 0 1 2
тогда как, если вытащить А В С из записи в переменные, в результате мы получим - 0 2 0 (последний 0 - "мусор", начальное состояние ячейки памяти, соответствующей переменной С).
Именно это я и нахожу забавным. Получается, память выделяется:
для отдельных переменных
Код: Выделить всё
А:_:В:_:С

а для элементов записи
Код: Выделить всё
Т.А:Т.В:Т.С

Неправильность подхода признаю.
Putnick
новенький
 
Сообщения: 62
Зарегистрирован: 18.03.2009 13:02:56

Re: Тип Currency. Подскажите, в чём прикол?

Сообщение SSerge » 12.10.2012 10:51:44

К вашему первому коду, при ограничении цикла до тройки:
Код: Выделить всё
  writeln(@a=@(tmp^[0]),' ',@b=@(tmp^[2]),' ',@c=@(tmp^[4]));
> TRUE TRUE TRUE


Выравнивание в действии, однако :D
SSerge
энтузиаст
 
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Re: Тип Currency. Подскажите, в чём прикол?

Сообщение naomika » 09.08.2013 11:55:05

ведь память за переменной С не выделена.
Подскажите, в чём я ошибаюсь?

Ответ заключен в самом вопросе :D
Аватара пользователя
naomika
незнакомец
 
Сообщения: 7
Зарегистрирован: 09.08.2013 08:30:41


Вернуться в Обучение Free Pascal

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 18

Рейтинг@Mail.ru