Несоответсвие типов VAR-параметров подпрограмм(error 26). |
1. Заголовок или название темы должно быть информативным !
2. Все тексты фрагментов программ должны помещаться в теги [code] ... [/code] или [code=pas] ... [/code].
3. Прежде чем задавать вопрос, см. "FAQ" и используйте ПОИСК !
4. НЕ используйте форум для личного общения!
5. Самое главное - это раздел теоретический, т.е. никаких задач и программ (за исключением небольших фрагментов) - для этого есть отдельный раздел!
Несоответсвие типов VAR-параметров подпрограмм(error 26). |
Neznaika |
13.07.2007 12:44
Сообщение
#1
|
Пионер Группа: Пользователи Сообщений: 51 Пол: Мужской Репутация: 0 |
Извиняюсь за возможное нарушение правил, но решил поместить пример программы,
чтобы сразу было понятно что к чему. ПРОГРАММА: Код program VarStr; uses Dos; procedure Proc( var Dir : DirStr; var Name : NameStr; var Ext : ExtStr ); begin end; procedure Proc2( var B : Byte; var W : Word; var L : LongInt ); begin end; procedure Proc3( var I : Integer; var W : Word ); begin end; procedure Proc21( B : Byte; W : Word; L : LongInt ); begin end; var SD, SN, SE : String; SDir : DirStr; SName : NameStr; SExt : ExtStr; B : Byte; W : Word; L : LongInt; I : Integer; begin (*Proc(SD,SN,SE); { НЕЛЬЗЯ! Ошибка 26: Type mismatch(несовпадение типов). }*) Proc(SDir,SName,SExt); { Всё в порядке! } (*Proc2(B,B{Error 26!},B);*) (*Proc2(W{Error 26!},W,W);*) (*Proc2(L{Error 26!},L,L);*) Proc2(B,W,L); { Всё в порядке! } (*Proc3(W{Error 26!},W);*) (*Proc3(W{Error 26!},I);*) (*Proc3(I,I{Error 26!});*) Proc3(I,W); { Всё в порядке! } Proc3(Integer(W),Word(I)); { Всё в порядке! } Proc21(B,W,L); { Всё в порядке! } Proc21(L,B,W); { Всё в порядке! } Proc21(W,L,B) { Всё в порядке! } end. И сам ВОПРОС(недеюсь он теоретический(имеет отношение к синтаксису, семантике и т.д. и т.п)): Почему типы фактических параметров переменных, задаваемых при вызове подпрограммы, должны СОВПАДАТЬ(быть РАВНЫМИ) соответствующим формальным VAR-параметрам. Почему здесь ошибка 26(Type mismatch) - НЕСООТВЕТСТВИЕ ТИПОВ превращается в ошибку НЕСОВПАДЕНИЕ ТИПОВ. Пожалуйста, если кто-нибудь знает, объясните. |
compiler |
13.07.2007 13:25
Сообщение
#2
|
Человек Группа: Пользователи Сообщений: 1 050 Пол: Мужской Реальное имя: Станислав Репутация: 3 |
procedure p( const s:string );что б не возникало подобных вопросов сделано так как сделано... -------------------- Спасибо!
Удачи! |
volvo |
13.07.2007 13:43
Сообщение
#3
|
Гость |
Цитата Почему здесь ошибка 26(Type mismatch) - НЕСООТВЕТСТВИЕ ТИПОВ превращается в ошибку Ничего никуда не превращается. Как всегда было Error 26 - Type Mismatch, так и есть Type Mismatch. То что тебе в одном случае хочется это перевести как "несоответствие", а в другом - как "несовпадение" - это не проблемы компилятора.НЕСОВПАДЕНИЕ ТИПОВ. Теперь о том, Цитата Почему типы фактических параметров переменных, задаваемых при вызове подпрограммы, должны СОВПАДАТЬ(быть РАВНЫМИ) соответствующим формальным VAR-параметрам Вот именно потому и должны совпадать, что процедуре будет передана не локальная копия переменной, с которой она будет работать, а адрес переменной, то есть, работа-то осуществляется непосредственно с той переменной, которая передана в качестве параметра. Отсюда следует что? Типы фактического и формального параметра в этом случае должны быть не просто совместимыми, они должны быть эквивалентны... И за этим компилятор следит.Кстати, частично твоя проблема очень просто решается добавлением в первую строку директивы {$V-}, которая отключает подобный контроль (только для строковых типов) со стороны компилятора. Сообщение отредактировано: volvo - 13.07.2007 13:44 |
Neznaika |
13.07.2007 16:14
Сообщение
#4
|
Пионер Группа: Пользователи Сообщений: 51 Пол: Мужской Репутация: 0 |
compiler:
Не смешно, мой пример СИНТАКСИЧЕСКИ КОРРЕКТЕН. volvo: Есть a) НЕСОВМЕСТИМОСТЬ ТИПОВ: например WORD := STRING или ARRAY := RECORD б) СОВМЕСТИМОСТЬ(НО НЕ РАВЕНСТВО) ТИПОВ: BYTE := WORD или REAL := LONGINT в) РАВЕНСТВО ТИПОВ: SHORTINT := SHORTINT, BYTE := BYTE, WORD := WORD и т.д. В операторе присваивания с совместимостью всё в порядке, в параметрах, передаваемых по значению, тоже. Но почему для
сработает это Код Proc3(I,W); и это Код Proc3(Integer(W),Word(I)); но не это Код Proc3(W,I); ??? |
volvo |
13.07.2007 16:31
Сообщение
#5
|
Гость |
Если ты не понял того, что написано в предыдущем посте, то чего бы я опять что-то тебе объяснял? Результат будет один и тот же. Тебе ясно сказано: для того, чтобы корректно работать с адресом передаваемым в качестве фактического параметра, типы должны быть ЭКВИВАЛЕНТНЫ, нет, ты опять начинаешь бодягу про совместимость типов... Совместимость - это по присваиванию, у тебя совсем другой вариант.
Что, действительно заняться нечем? Тогда иди, почитай доки, что-ли... Цитата сработает это То, что оно компилируется в Турбо Паскале - еще не значит, что оно ДОЛЖНО там компилироваться, вот мой компилятор такого не пропускает, чтоб неповадно было. Проходит только эквивалентный тип. Смени компилятор, и убедись...... Код Proc3(Integer(W),Word(I)); |
Neznaika |
13.07.2007 18:02
Сообщение
#6
|
Пионер Группа: Пользователи Сообщений: 51 Пол: Мужской Репутация: 0 |
volvo:
Я не хочу ругаться, я разобраться хочу. Просто ошибка в этом месте у меня несколько раз появлялась. Если TP не устраивает, тогда на Delphi(Win32): Код procedure Proc1( var I : Integer; var W : Word ); begin end; procedure Proc2( var I : SmallInt; var W : Word ); begin end; var I : Integer; { 4 bit } W : Word; { 2 bit } SI : SmallInt; { 2 bit } D : DWord; { 4 bit } begin Proc1(I,W); Proc1(D,Word(D)); { Proc1(D,D) - не работает! } Proc2(SI,W); Proc2(SmallInt(W),Word(SI)); end. Например есть число, которое будет обрабатываться как 32-разрядное, а инициализируется оно например вызовом некоторой процедуры как 16-разрядное. ИЛИ числа со знаком и без знака, но их SizeOf(Type1) = SizeOf(Type2). Эквивалентность и равенство - это одно и то же или нет? Если по-вашему выходит, что ЭКВИВАЛЕНТНОСТЬ = РАВЕНСТВО, то как Delphi пропускает Proc1(D,Word(D)); ??? Я понимаю, что здесь в процедуру передаётся адрес ячейки памяти, названной D(на этапе объявления переменных компилятор отвёл под неё 4 байта, записал в своих таблицах, что её тип DWord, ещё что-то там сделал). Ещё здесь(при генерации вызова процедуры) компилятор проверяет типы фактических параметров. Но при этом никакого ПРЕОБРАЗОВАНИЯ/ПРИВЕДЕНИЯ ТИПОВ не происходит, компилятор просто генерирует push VarAddr call Proc или mov reg, VarAddr call Proc Тоже самое он сгенерирует для переменной правильного типа(как у VAR-параметра). Сама процедура просто тупо скопирует значение результата в ячейку по переданному ей адресу. Мне непонятно, почему нельзя Proc1(D,D), а нужно обязательно Proc1(D,Word(D))??? Сообщение отредактировано: Neznaika - 14.07.2007 15:27 |
Neznaika |
14.07.2007 15:49
Сообщение
#7
|
Пионер Группа: Пользователи Сообщений: 51 Пол: Мужской Репутация: 0 |
Вот например, что написано у Епанешниковых(Программирование в среде Turbo Pascal 7.0):
10.3.2. Параметры переменные Цитата При вызове подпрограммы на месте параметра-переменной в качестве фактического параметра должна использоваться переменная идентичного типа(см п 9.1). Смотрим пункт 9.1: Цитата Идентичность типов Идентичность типов требуется от формальных параметров процедур и функций и соответствующих им фактических параметров во время вызова. Два типа T1 и T2 идентичны в следующих случаях: 1) T1 и T2 - один и тот же идентификатор типа(например, Integer, Real и т.д.); 2) один тип объявляется эквивалентным другому. Пример type T1 = Boolean; T2 = T1; T3 = Boolean; Все типы T1, T2, T3 и Boolean - идентичные типы. type M1 = array[1..5] of Integer; M2 = array[1..5] of Integer; Типы M1 и M2 - не идентичные типы. Однако V1 и V2 - переменные идентичных типов: var V1, V2 : array[1..5] of Integer; Получается, что типы данных формальных и фактических VAR-параметров просто должны совпадать, но это не так! И Turbo Pascal и Delphi нормально компилируют Type1(VarType2) (здесь VAR-параметр имеет тип Type1, а переменная VarType2 - соответственно Type2) если Type1 является подмножеством Type2. |
compiler |
14.07.2007 16:05
Сообщение
#8
|
Человек Группа: Пользователи Сообщений: 1 050 Пол: Мужской Реальное имя: Станислав Репутация: 3 |
Получается, что типы данных формальных и фактических VAR-параметров просто должны совпадать, но это не так! И Turbo Pascal и Delphi нормально компилируют тебе же написали Цитата То, что оно компилируется в Турбо Паскале - еще не значит, что оно ДОЛЖНО там компилироваться а еще многие ошибки вообще не отлавливаются во время компиляции.. Сообщение отредактировано: compiler - 14.07.2007 16:05 -------------------- Спасибо!
Удачи! |
Neznaika |
14.07.2007 16:52
Сообщение
#9
|
Пионер Группа: Пользователи Сообщений: 51 Пол: Мужской Репутация: 0 |
тебе же написали а еще многие ошибки вообще не отлавливаются во время компиляции.. Я так не думаю. По-моему использование в качестве фактического VAR-параметра переменной совместимого (расширенного) типа - это не ошибка, а вполне нормальное явление. Не могу привести никаких ссылок, но я где-то встречал примеры такого способа передачи параметров. Повторяю: И Turbo Pascal и Delphi нормально компилируют Type1(VarType2) (здесь VAR-параметр имеет тип Type1, а переменная VarType2 - соответственно Type2) если Type1 является подмножеством Type2. Компилятор пишут одни люди, документацию другие. Например в моей версии Delphi в помощи на синтаксических диаграммах для CASE указано, что перед ELSE ";"(точку с запятой) ставить нельзя. На самом же деле её можно и ставить и не ставить!!! Проблема не в компиляторе, а в ДОКУМЕНТАЦИИ! |
volvo |
14.07.2007 16:58
Сообщение
#10
|
Гость |
Цитата И Turbo Pascal и Delphi нормально компилируют Дельфи? Сорри, только не Дельфи:Что я делаю не так? Цитата Получается, что типы данных формальных и фактических VAR-параметров просто должны совпадать Это некорректное определение эквивалентности. Вот эти типы - эквивалентны, хотя в первом случае они "одинаковы", а во втором - совсем нет:type Вот эта программа действительно компилируется как в FPC, так и в Delphi... Потому, что компилироваться должна. Добавлено через 1 мин. P.S. Повторяю, Дельфи - НЕ компилирует... Еще раз повторить? |
Neznaika |
14.07.2007 17:07
Сообщение
#11
|
Пионер Группа: Пользователи Сообщений: 51 Пол: Мужской Репутация: 0 |
Только что скомпилировал. Я не вру. Сообщение отредактировано: Neznaika - 14.07.2007 17:13 |
мисс_граффити |
14.07.2007 19:57
Сообщение
#12
|
просто человек Группа: Модераторы Сообщений: 3 641 Пол: Женский Реальное имя: Юлия Репутация: 55 |
Естественно.
А где в этом примере несоответствие может возникнуть? -------------------- Все содержимое данного сообщения (кроме цитат) является моим личным скромным мнением и на статус истины в высшей инстанции не претендует.
На вопросы по программированию, физике, математике и т.д. в аське и личке не отвечаю. Даже "один-единственный раз" в виде исключения! |
volvo |
14.07.2007 21:07
Сообщение
#13
|
Гость |
Цитата Только что скомпилировал. Разговор был про Var-параметры... Попробуй добавитьprocedure Proc(VAR W : Word; DW : DWord ); // <--- Вот этот Var и теперь откомпилировать... |
Neznaika |
14.07.2007 23:22
Сообщение
#14
|
Пионер Группа: Пользователи Сообщений: 51 Пол: Мужской Репутация: 0 |
Тьфу, чёрт. Теперь вроде всё "правильно". Delphi 2.0 транслирует.
|
Neznaika |
18.07.2007 16:42
Сообщение
#15
|
Пионер Группа: Пользователи Сообщений: 51 Пол: Мужской Репутация: 0 |
BDS2006(компилятор Delphi для Win32):
Delphi 2.0:
Уважаемые эксперты, объясните пожалуйста 1) Что означает ошибка "Constant object cannot be passed as var parameter" в случае BDS2006 и в случае Delphi2 ??? 2) Если типы VAR-параметров должны быть "идентичны", почему тогда компилятор пропускает Proc(Word((@B)^),DWord((@B)^)); ??? 3) Дайте пожалуйста определение эквивалентности(как написал volvo) типов формальных и фактических VAR-параметров. Спасибо заранее. |
hardcase |
8.08.2007 21:16
Сообщение
#16
|
code warrior Группа: Пользователи Сообщений: 484 Пол: Мужской Реальное имя: Славен Репутация: 8 |
Уважаемые эксперты, объясните пожалуйста 1) Что означает ошибка "Constant object cannot be passed as var parameter" в случае BDS2006 и в случае Delphi2 ??? Приведение типа приводит к созданию временной локальной копии объекта, которая трактуется копилятором как константа приводимого типа. 2) Если типы VAR-параметров должны быть "идентичны", почему тогда компилятор пропускает Proc(Word((@B)^),DWord((@B)^)); ??? Дело в том, что по умолчанию операция получения адреса @ "теряет" тип объекта. Разыменовывая указатель операцией ^ мы получаем некий объект, который не имеет типа; для того чтобы с ним работать компилятору требуется явно указать тип адресованного объекта - в этом случае операция приведения типа не создает локальной копии, ибо выполняется на этапе компиляции. -------------------- ИзВ ин ИтЕ зА нЕ рОв НЫй П оч ЕРк
|
Neznaika |
11.08.2007 16:36
Сообщение
#17
|
Пионер Группа: Пользователи Сообщений: 51 Пол: Мужской Репутация: 0 |
Цитата Приведение типа приводит к созданию временной локальной копии объекта, которая трактуется копилятором как константа приводимого типа. hardcase, спасибо. Но всё равно, тёмное дело. Во второй версии Delphi вызов с Type1(VariableOfType2) производит только проверку совместимости(как я написал раньше вместо W можно указать Word(DW), но не Word(B)). В Delphi 6 (судя по картинке volvo) и в BDS2006 компилятор похоже действительно пытается создать локальную копию объекта. Цитата Дело в том, что по умолчанию операция получения адреса @ "теряет" тип объекта. Разыменовывая указатель операцией ^ мы получаем некий объект, который не имеет типа; для того чтобы с ним работать компилятору требуется явно указать тип адресованного объекта - в этом случае операция приведения типа не создает локальной копии, ибо выполняется на этапе компиляции. Мне кажется, что оба действия - и Type1(Type2Variable) и Type1((@Type2Variable)^) - выполняются на этапе компиляции. Но почему в первом случае создаётся локальная копия(для VAR-параметров), по какому синтаксическому правилу? Можно где-нибудь об этом узнать? |
volvo |
11.08.2007 17:00
Сообщение
#18
|
Гость |
Neznaika, во-первых, будет ли твоя программа компилироваться в Дельфи (в частности, в D6 - ибо из BDS2006 у меня установлен только Builder, так что проверить не могу), зависит напрямую от установок директив компиляции. К примеру, при добавлении первой строкой модуля: {$T+} твое утверждение:
Цитата компилятор пропускает становится ложным, хотя при {$T-} все компилируется...Proc(Word((@B)^),DWord((@B)^)); ??? А какие там значения директив по умолчанию на твоем компьютере выставлены - это я не знаю, и догадываться тоже не особо хочется... Сообщение отредактировано: volvo - 11.08.2007 17:00 |
Neznaika |
11.08.2007 17:41
Сообщение
#19
|
Пионер Группа: Пользователи Сообщений: 51 Пол: Мужской Репутация: 0 |
Да, с {$T+} Proc(Word((@B)^),DWord((@B)^)); не компилируется в любой версии Delphi
(даже во второй, хотя в ней проходит Proc(Word(DW),DW); для procedure Proc( var W : Word; var DW : DWord );). А можно ли вообще использовать в качестве фактических параметров процедур для VAR-параметров ВЫРАЖЕНИЯ? Для W типа Word конструкция Byte(W) - это выражение. P.S. Эх. Наверное надо было с самого начала так ставить вопрос... |
hardcase |
11.08.2007 18:23
Сообщение
#20
|
code warrior Группа: Пользователи Сообщений: 484 Пол: Мужской Реальное имя: Славен Репутация: 8 |
Есть такое понятие в программировании - безопасный код.
Помимо всего прочего (про exceptionы и потокобезопасность здесь речь не пойдет) оно включает в себя стиль написания программы, который не допускает работу с указателями в явной форме - получение, разыменование, арифметика на ним, также не приветствуются операции приведения типов. Вместо указателей настоятельно рекомендуется использовать ссылки, а типы преобразовывать в явном виде - через операции присваивания, встроенные функции и т.п. Т.е. нужно как можно больше работы сбрасывать на компилятор - статический контроль типов, управление памятью и прочую рутину. Он умеет это лучше чем человек. Теперь по поводу совместимости и эквивалентности. Совместимость типов - это такое отношение между двумя типами, которое доступно компилятору на этапе синтаксического анализа исходника. Т.е. компилятор ЗНАЕТ как перевести тип А в тип Б. Например real совместим с integer (переменной типа real можно присвоить значение переменной типа integer), но не наоборот. Эквивалентность типов - имеется в виду двоичная эквивалентность, это отношение между типами, выстроенное на основе размера памяти в байтах, который занимает переменная того или иного типа. Например у нас есть запись вида: Код TMyDWord = packed record HiWord: Word; LoWord: Word; end; Если мы имеем переменную типа Dword то мы вполне можем привести её к типу TMyDWord. Это приведение допустимо потому что размер занимаемый TMyDword равен размеру DWord. Обратное приведение также возможно. Эквивалентность типов может зависеть от настроек компилятора. Если мы поставим выравнивание полей записи по 4 байтам (это сильно ускорит их обработку) приведенный выше пример не будет работать, так как размеры перестанут совпадать и отношение двоичной эквивалентности между типами пропадет. Операция приведения типа оперирует с понятием эквивалентности типов. Мы можем привести тип А к типу Б в том случае, когда size(А) >= size(Б). Это ограничение не позволит обратиться к, возможно, невыделенной области памяти, что приведет к AV-исключению. При передаче параметров в подпрограммы или методы, для компилятора очень важен ТИП подставляемх фактических параметров, именно на основе их типов, он будет вызывать нужную перегруженную версию (если они есть) сабрутины. Отсюда правило - нужно ЗНАТЬ что ты хочешь сделать, чтобы небыло недопонимания с компилером. Цитата Мне кажется, что оба действия - и Type1(Type2Variable) и Type1((@Type2Variable)^) - выполняются на этапе Я уже объяснял..... Первый вариант приводит к копированию данных во временную переменную. Второй вариант компилятор рассматривает как некое переобъявление переменной. Разыменованный указатель - это переменная, операция приведения типа выступает в качестве декларирования типа переменной. Именно поэтому такая запись пригодна для передачи параметра по ссылке.компиляции. Но почему в первом случае создаётся локальная копия(для VAR-параметров), по какому синтаксическому правилу? Добавлено через 6 мин. Ваял предыдущий креатив..... А можно ли вообще использовать в качестве фактических параметров процедур для VAR-параметров ВЫРАЖЕНИЯ? Для W типа Word конструкция Byte(W) - это выражение. В принципе - можно. Если выражение своим результатом возвращает указатель, то используя технику дзен Код Type1((PType1PointerExpression)^) Мы можем передавать данные по ссылке. Другое дело, что нам потребуется написать выражение, результатом которого будет некий указаталь (с точки зрения безопасного кода подобные действия никуда не годятся). -------------------- ИзВ ин ИтЕ зА нЕ рОв НЫй П оч ЕРк
|
Текстовая версия | 29.04.2024 9:34 |