Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2011.12.18;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.5 MB
Время: 0.004 c
1-1277656298
DeusNoxious
2010-06-27 20:31
2011.12.18
Интерактивный Google maps


2-1315318888
Gu
2011-09-06 18:21
2011.12.18
Dll метод


15-1314348069
androidios
2011-08-26 12:41
2011.12.18
Нужно перевести 2 функции с php на delphi за $


2-1315739001
я
2011-09-11 15:03
2011.12.18
ftGraphic, DBGrid,ClientDataSet,DataSource


8-1221298606
Grinya
2008-09-13 13:36
2011.12.18
карта в масштабе





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский