Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2011.12.18;
Скачать: CL | DM;

Вниз

Последовательность вычисления параметров   Найти похожие ветки 

 
RAD   (2011-09-10 03:01) [0]

Здравствуйте !

В коде встречается следующая конструкция:


       Client.AddIncomingMessage(
         R.ReadInteger(),  
         0,                
         R.ReadTimeStamp(),
         R.ReadBytes()      
       );


Проблема (точнее вопрос - так как проблема легко решается обходным маневром с временными переменными) в том, что последовательность выполнения процедур при отладке обнаруживается следующая:
1. R.ReadTimeStamp(),
2. R.ReadBytes()      
3. R.ReadInteger()
а не
1. R.ReadInteger()
2. R.ReadTimeStamp(),
3. R.ReadBytes()      
как ожидалось...
Оптимизация в опциях компилятора отключена. Чем можно объяснить такую странную последовательность в вычислении параметров функции и можно ли как-то повлиять на порядо их вычисления.

Delphi 2009


 
MBo ©   (2011-09-10 08:02) [1]

>Чем можно объяснить такую странную последовательность в вычислении параметров функции
Соглашение о вызове по умолчанию register
Параметры слева направо
eax edx ecx, остальные пихаются в стек
eax  занимает Self, два левых параметра в регистрах, два правых в стеке - вот они раньше и вычисляются.
Поскольку порядок вычисления параметров недокументирован, полагаться на него нельзя, и надо просто принять меры, чтобы он не влиял


 
Anatoly Podgoretsky ©   (2011-09-10 09:53) [2]


> Чем можно объяснить такую странную последовательность в
> вычислении параметров функции и можно ли как-то повлиять
> на порядо их вычисления.

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


 
Полвторого   (2011-09-10 13:35) [3]

> Поскольку порядок вычисления параметров недокументирован, полагаться на него нельзя
+1.
Лучше заранее прочитать то что требуется, в нужной последовательности.
Для программиста это как «правило хорошего тона».


 
Inovet ©   (2011-09-10 15:45) [4]

> [3] Полвторого   (10.09.11 13:35)
> Для программиста это как «правило хорошего тона».

Client.AddIncomingMessage(
 R.ReadInteger(),  
 0,                
 R.ReadTimeStamp(),
 R.ReadBytes()      
);

Вообще-то Read в названии функции по правилам хорошего тона должен означать, что функция не приводит к изменениям состояния объекта.


 
Полвторого   (2011-09-10 16:19) [5]


> Inovet ©   (10.09.11 15:45) [4]

Это если чтение производится откуда-то из полей объекта.
А что если подразумевается чтение, скажем, с какого-нибудь сокета?


 
Inovet ©   (2011-09-10 16:35) [6]

> [5] Полвторого   (10.09.11 16:19)
> А что если подразумевается чтение, скажем, с какого-нибудь сокета?

Если между чтенимя от времени или от последовательности есть неоднозначность, значит надо возвращать в структуре взаимно согласованные данные. Это же всё-таки не программа драйвера устройства, а нечто высокоуровневое.


 
Игорь Шевченко ©   (2011-09-10 17:31) [7]

Inovet ©   (10.09.11 16:35) [6]


> Read в названии функции по правилам хорошего тона должен
> означать, что функция не приводит к изменениям состояния
> объекта.


RTFM: TStream.Read


 
Inovet ©   (2011-09-10 17:50) [8]

> [7] Игорь Шевченко ©   (10.09.11 17:31)
> RTFM: TStream.Read

Причём тут чтение из стрима, из него читается однородные данные, а в сабже разные куски одной структуры, которые читаются по разному от времени и последовательности, раз автор озадачился последовательностью. Вот и надо читать сразу цельную структуру. Ты с этим не согласен значит?


 
Inovet ©   (2011-09-10 17:55) [9]

> [8] Inovet ©   (10.09.11 17:50)
> Причём тут чтение из стрима

Понял к чему ты. Что в стриме разное может быть и читать можно разными методами.


 
Игорь Шевченко ©   (2011-09-10 18:51) [10]

Inovet ©   (10.09.11 17:55) [9]

Я к тому, что метод TStream.Read вызывает изменение объекта TStream


 
RAD   (2011-09-11 00:39) [11]

Спасибо все. Признаю - глупость сморозил полную - забыл, после жабы, что в дельфе соглашение fastcall по умолчанию. Каюсь :)


> Вообще-то Read в названии функции по правилам хорошего тона
> должен означать, что функция не приводит к изменениям состояния
> объекта.

Видимо, программисты Borland об этих правилах не слышали - большинство их методов ReadXXX изменяют состояние объекта. См. TStream, TReader etc.
p.s. Я кстати, тоже такого не слышал.


> Никто и не обещал определенного порядка, так что все в соответствии
> с документацией, и влиять нужды нет, кроме разве дурного
> кода.

По умолчанию - не обещали. А вот при установке конкретного соглашения вызова - в моем случае это будет pascal - таки да - обещали и обязаны следовать.
А что касается дурного кода - что дурнее написать как озвучено выше + соглашение вызова или описать 3 дополнительные вспомогательные переменные ? ИМХО, вопрос спорный.


> MBo ©   (10.09.11 08:02) [1]

Спасибо :)


 
Германн ©   (2011-09-11 01:34) [12]


>
> По умолчанию - не обещали. А вот при установке конкретного
> соглашения вызова - в моем случае это будет pascal - таки
> да - обещали и обязаны следовать.

Вот только бредить не надо!


 
RAD   (2011-09-11 02:11) [13]


> Вот только бредить не надо!

Может еще и аргументировать сможешь ? Или только покричать ?


 
Полвторого   (2011-09-11 04:50) [14]


> RAD   (11.09.11 02:11) [13]

Аргументировать смогу я.
Порядок обработки параметров никто нигде не регламентировал.
Рассмотрим ассемблерный код (в данном случае это директива stdcall, однако смысл не меняется):

MOV EDI, Param2;
MOV ESI, Param3;
PUSH ESI;
MOV ESI, Param1;
PUSH ESI;
PUSH EDI;
CALL Function;


Параметры обрабатываются в порядке 2-3-1 (т.е. если бы на переменных Param1,Param2 и Param3 стояли точки останова по чтению, они бы отработали именно в такой последовательности).

Хотя, если происходит обычное чтение из переменных — разницы и впрямь никакой не будет. Однако если параметры вычисляются сразу во время заполнения стэка — жди беды.

И ничто не мешает компилятору поступать именно так. И резонов для этого может быть море-разливанное: начиная от серьёзной оптимизации по кэшу, и заканчивая тем, что функция, отдающая, скажем, третий параметр, у компилятора в таблице дескрипторов стояла раньше, чем та, что возвращает второй. Очевидно, что от версии к версии поведение компиляторов может меняться.

Делайте выводы…


 
Германн ©   (2011-09-11 10:41) [15]


> RAD   (11.09.11 02:11) [13]
>
>
> > Вот только бредить не надо!
>
> Может еще и аргументировать сможешь ?

А что тут аргументировать? Соглашение о вызовах подразумевает только порядок передачи входных параметров в процедуру. При этом никакой речи не идет о вызовах иных процедур!


 
Inovet ©   (2011-09-11 12:27) [16]

> [11] RAD   (11.09.11 00:39)
> См. TStream, TReader etc.
> p.s. Я кстати, тоже такого не слышал.

Дался вам этот поток, с ним всё нормально как раз.

Пример. Допустим есть функция ReadDuration() которая возвращает время с начала выполнения действия объекта. Возвращает она в записи с полями Day, Hour, Min, Sec - всё нормально. Теперь предположим что это время возможно узнать только с помощью функций ReadDurationDay(), ReadDurationHour(), ReadDurationMin(), ReadDurationSec() они возвращзаю целые, но никто не даёт никакой гарантии, что последовательно вызвав эти функции и объёдинив результат, время будет соответсвовать действительности.

Другой пример. Получить координаты указателя мыши зразу записью x, y или сначала х, потм мышь сдвинулась и следующим вызовом y.

И самое интересное. если функция получения координаты x при этом сама будет двигать указатель для спец эффектов.


 
Полвторого   (2011-09-11 14:37) [17]


> Дался вам этот поток, с ним всё нормально как раз.

Положим, у нас есть неименованный канал, в котором ждут своей очереди на чтение один байт, одно слово и одно двойное слово:
|__|____|________|
Пусть у нас есть функции ReadByte, ReadWord и ReadLongWord.
Что случится, если их запустить в неверном порядке?
Ну, например, сначала в прочитанное двойное слово попадут байт (две старших тетрады), слово целиком, и старший байт двойного слова в младшую позицию. Ну и далее в том же духе.

Так что с потоком может быть далеко не «всё нормально».


 
Inovet ©   (2011-09-11 17:37) [18]

> [17] Полвторого   (11.09.11 14:37)
> Так что с потоком может быть далеко не «всё нормально».

Об этом я говорил в ответе ИШ. Это уже нетипизированное чтение. Можно читать побайтно или в буфер и разбирать. Можно добавить ReadMyType, в ней реализовать один раз правильную последовательность чтений, и потом везде читать сразу как надо, хоть в буфер этих MyType.



Страницы: 1 вся ветка

Текущий архив: 2011.12.18;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.009 c
2-1315838395
Pcrepair
2011-09-12 18:39
2011.12.18
как подключить модуль в RAD2010


2-1313176699
Leon-Z
2011-08-12 23:18
2011.12.18
Размер BLOB поля.


15-1314915157
картман
2011-09-02 02:12
2011.12.18
посоветуйте UPS


1-1277278827
azatsh
2010-06-23 11:40
2011.12.18
как открыть dll засунутую вexe шник как ресурс


15-1313768120
Омлет
2011-08-19 19:35
2011.12.18
Яндекс упал...