Форум: "Начинающим";
Текущий архив: 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