Форум » Clipper » Засада в OemToAnsi » Ответить

Засада в OemToAnsi

les: Давно написанная и отлично работающая OemToAnsi понадобилась в другом проекте. я её выделил в отдельный PRG файл, откомпилировал, добавил в свою библиотеку - всё работает. НО случайно обнаружил "красный эффект" - портится ПАРАМЕТР! т.е. Funcion OemToAnsi( cOem ) Local cAnsi := cOem // перекодировка cAnsi, сюда запостить не получится - там одновременно и DOS и Win кодировки ........ Return cAnsi выполнятся cOem := 'Тест' cAnsi := OemToAnsi( cOem ) в результате cOem == cAnsi в старом проекте (где функция не из библиотеки ) этого не происходит. не могу понять - где засада

Ответов - 16

Dima: les Пробуй [pre] func oemtoansi(srt) local j:=len(srt) local i : =1 local ret:="" local asco:="" for i=1 to j asco:=substr(srt,i,1) if asc(asco)<128 ret+=asco elseif asc(asco)>=128 .and. asc(asco)<=175 ret+=chr(asc(asco)+64) elseif asc(asco)>=224 .and. asc(asco)<=239 ret+=chr(asc(asco)+16) else ret+="" endif next RETURN ret [/pre]

les: Dima пишет: Пробуй Спасибо конено, у меня тоже есть аналогичная ф-я. вопрос не в методе пекодивки, а почему меняется ПАРАМЕТР. Причём только если прилинковуется из библиотеки. Я просто в шоке

sergey5703: Попробуйте изменить оператор RETURN cAnsi на RETURN (cAnsi). Все дело в том, что когда возвращается выражение в скобках то возвращается ЗНАЧЕНИЕ, а в Вашем случае возвращается ССЫЛКА!


les: sergey5703 пишет: Попробуйте изменить оператор RETURN cAnsi на RETURN (cAnsi). Все дело в том, что когда возвращается выражение в скобках то возвращается ЗНАЧЕНИЕ, а в Вашем случае возвращается ССЫЛКА! Спасибо - помогло Это я знаю, но раньше на эти грабли не наступал. Я в шоке. Каким образом ссылка на локальную для функции переменную cAnsi может повлиять на параметр cOem и переменную вызывающей программы Почему функция входящая в состав проекта и прилинкованая из библиотеки ведут себя по-разному

suv2: Ничего подбного, все не правы. Никакие скобки тут не при чем. return Ansi и return (Ansi) - это одно и то же, возвращается значение. В этом легко убедиться, сравнив побайтно (fc.exe /b) код, получаемый при компиляции. А переменная вне функции может изменить свое значение только в том случае, если была передана в функцию по ссылке - OemToAnsi(@cOem) Почему переменная всё-таки меняет свое значение, когда функция из библиотеки - легко объяснимо. На клиппере такого эффекта достичь нельзя, как сказано выше. Следовательно, если функция на клиппер и непосредственно в текстах программы - такого эффекта не наблюдается, потому что в первую очередь для разрешения неопределенных ссылок используются объектные модули. А вот когда ты ее помещаешь в библиотеку - линковщик после просмотра OBJ ищет неразрешенные ссылки в библиотеках, в порядке их указания. Скорее всего, в одной из твоих библиотек есть функция точно с таким же именем, которая написана на ассемблере. В этом легко убедиться, сделав листинг всех библиотек - ты найдешь ее. Так же в подтверждение этой теории ты можешь вообще выкинуть свою функцию на клиппере - слинкуется без ошибок. И написана эта ассемблерная функция неправильно. Обычно, при программировании на ассемблере под клиппер необходимо прилагать значительные усилия, чтобы не изменить параметр - выделять память (а вдруг переменная большая (64К) и в данный момент такого куска свободной памяти не будет, что тогда?), копировать туда значение. Поэтому возникает соблазн большой получить ссылку на параметр (про который в руководстве по экстенд систем сказано - менять его НЕЛЬЗЯ) и сделать перекодировку непосредственно там, при этом переменная конечно же портится. Фактически, в твой фрагмент эквивалентен следующему cOem := 'Тест' cAnsi := OemToAnsi( @cOem ) - передача по ссылке поэтому меняются и cAnsi и сама cOem Если тебе важна скорость работы можешь оставить библиотечную ассемблерную функцию, но при этом учитывать ее особенности. Например, если тебе нужно старое значение - можешь создать его копию. Также, ты можешь указать свою библиотеку самой первой и увидишь, что переменная больше не портится, потому что будет работать твоя функция на клиппере. Также ты можешь не менять порядок линковки, но удалить ассемблерную функцию из библиотеки.

les: suv2 пишет: Ничего подбного, все не правы. Никакие скобки тут не при чем. return Ansi и return (Ansi) - это одно и то же, возвращается значение. Тем неменее после заключения в скобки функция стала работать нормально. suv2 пишет: Когда ты ее помещаешь в библиотеку - линковщик ищет неразрешенные ссылки в порядке указания библиотек. Скорее всего в в одной из твоих библиотек есть функция точно с таким же именем, которая написана на ассемблере. В этом легко убедиться, сделав листинг всех библиотек - ты найдешь ее. Убирал из своей библиотеки и из текста проекта линковщик ищет неразрешенные ссылки, и не находит. suv2 пишет: Фактически, в твой фрагмент эквивалентен следующему cOem := 'Тест' cAnsi := OemToAnsi( @cOem ) - передача по ссылке поэтому меняются и cAnsi и сама cOem 1. я передаю не по ссылке 2. в функции есть Local cAnsi := cOem и перекодируется cAnsi а не cOem

suv2: les пишет: Тем неменее после заключения в скобки функция стала работать нормально После - не в следствии. Давай я не буду гадать, что ты там еще напутал и поменял, когда добавил скобки. Ты мог изменить порядок линковки библиотек, мог еще чего-то поменять, не заметить и так далее. Повторяю - 1) return (ansi) и return ansi - это ОДНО И ТО ЖЕ 2) никогда и ни при каких обстоятельствах на клиппер ты не сможешь изменить параметр внутри функции, если он не передавался по ссылке. Если ты утверждаешь, что 1) и 2) неверно - сделай тестовый пример, полностью самостоятельный, чтобы его мог проверить любой. Библиотека в которой лежит OemToAnsi на клиппер и больше ничего+PRG с тестом, в котором меняется переменная вне функции и показывается разница между return (ansi) и return ansi + BAT с компиляцией и линковкой + скрипты линковки без использования дополнительных библиотек, кроме стандартных. Обычно, когда доходит дело до тестового примера - его сделать не удается. Это и значит, что ты чего-то не замечаешь. les пишет: Убирал из своей библиотеки и из текста проекта линковщик ищет неразрешенные ссылки, и не находит. это полностью подтверждает мою теорию les пишет: 1. я передаю не по ссылке 2. в функции есть Local cAnsi := cOem и перекодируется cAnsi а не cOem ты невнимательно читаешь. Речь идет о том, что при невольном использовании ассемблерной функции твой фрагмент становится эквивалентен передаче по ссылке

les: suv2 пишет: ты невнимательно читаешь. Речь идет о том, что при невольном использовании ассемблерной функции твой фрагмент становится эквивалентен передаче по ссылке suv2 пишет: После - не в следствии. Давай я не буду гадать, что ты там еще напутал и поменял, когда добавил скобки. Ты мог изменить порядок линковки библиотек, мог еще чего-то поменять, не заметить и так далее. Повторяю - 1) return (ansi) и return ansi - это ОДНО И ТО ЖЕ 2) никогда и ни при каких обстоятельствах на клиппер ты не сможешь изменить параметр внутри функции, если он не передавался по ссылке. Если ты утверждаешь, что 1) и 2) неверно Я всегда свято в это верил. А насчёт поменял - так только скобки suv2 пишет: ты невнимательно читаешь. Речь идет о том, что при невольном использовании ассемблерной функции твой фрагмент становится эквивалентен передаче по ссылкета чтобы там не делалось оно делается с cAnsi причём тут cOem?

suv2: les пишет: та чтобы там не делалось оно делается с cAnsi причём тут cOem? Я же объяснял - если функция на ассемблере - она может поменять что угодно. Даже если ты передавал по значению, а не по ссылке. Это же ассмеблер) Вот это для кого написано было? - "Обычно, при программировании на ассемблере под клиппер необходимо прилагать значительные усилия, чтобы не изменить параметр - выделять память (а вдруг переменная большая (64К) и в данный момент такого куска свободной памяти не будет, что тогда?), копировать туда значение. Поэтому возникает соблазн большой получить ссылку на параметр (про который в руководстве по экстенд систем сказано - менять его НЕЛЬЗЯ) и сделать перекодировку непосредственно там, при этом переменная конечно же портится." Другими словами. Функция на ассемблере может напрямую работать с переданным параметром и это ее личное дело, создавать ли копию этого параметра, чтобы он не изменился или не создавать. Это только в языках высокого уровня автоматически без твоего участия происходит передача по значению и ты думаешь, что это происходит само-собой. Но на самом деле для передачи по значению необходимо прилагать определенные программные усилия, на которых программисты экономят. Для ассемблера возможно всё - можно изменить что угодно, хоть переменную внутри функции, хоть переменную в другой программе, запущенной до текущей, хоть любой произвольный участок памяти. Функция спрашивает у клиппера адрес параметра и меняет его, не соблюдая никаких соглашений по видимости и по передаче параметров. На клиппере ты таких результатов не получишь никогда. Если параметр меняется - значит виноват ассемблер, так может сделать только он. И никакие скобки не при чем.

Григорьев Владимир: suv2 пишет: Обычно, при программировании на ассемблере под клиппер необходимо прилагать значительные усилия, чтобы не изменить параметр - выделять память (а вдруг переменная большая (64К) В Clipper никакая переменная не может быть больше 64K. Максимальный размер строковой переменной меньше, чем 64K, за счет специального префикса, который выдяется под системные нужды. По крйней мере 14 байтов надо вычесть из 64K.

suv2: Григорьев Владимир пишет: В Clipper никакая переменная не может быть больше 64K читай внимательно, там не написано "больше 64к", там написано "большая (64к)"

les: suv2 пишет: Функция спрашивает у клиппера адрес параметра и меняет его, не соблюдая никаких соглашений по видимости и по передаче параметров. В моей ф-и OemToAnsi используется ф-я CharRepl() из CT III от CA, и я сомневаюсь что её писал школьник suv2 пишет: На клиппере ты таких результатов не получишь никогда. Если параметр меняется - значит виноват ассемблер, так может сделать только он. Моя ф-я на Clipper 5.2e И никакие скобки не при чем. Не спорю, но тем не менее... мистика Кстати тестовый пример работает как со скобками так и без.

suv2: les пишет: Кстати тестовый пример работает как со скобками так и без. Всё, тупик. абсолютно бессодержательный ответ. Могу лишь повторить выводы. Никакой порчи переменных на клиппер получить нельзя. Тестового примера нет и НЕ БУДЕТ Переменные у тебя портит другая функция с таким же именем OemToAnsi, написанная похабно. return (Ansi) и return Ansi - это одно и то же, между ними нет НИКАКОЙ разницы

Григорьев Владимир: les пишет: В моей ф-и OemToAnsi используется ф-я CharRepl() из CT III от CA, и я сомневаюсь что её писал школьник На самом деле функции из этой библиотеки написаны крайне плохо! Как-то был вопрос по поводу одной функции здесь на форуме, и, отвечая на вопрос, я ее восстановил по объектному коду. Могу подтвердить, что та функция написана бездарно и с ошибками. Так что не следует доверять этой библиотеке. Ее код крайне некачественный.

suv2: Григорьев Владимир пишет: На самом деле функции из этой библиотеки написаны крайне плохо! +1. И сам клиппер написан препохабнейше. обращения к неинициализированным переменным, запутанная логика, излишние усложнения, отсутствие контроля ошибок. но цэ-тулз - это нечто из ряда вон

Pasha: К слову. Пишу сейчас на харборе, и получил по лбу граблями, описанными в этой теме. В функции на С не сделал копию Item, и в результате после работы функции параметр изменил значение



полная версия страницы