var аргументы процедуры

Форум для изучающих FPC и их учителей.

Модератор: Модераторы

var аргументы процедуры

Сообщение trifon » 19.02.2008 23:43:35

корректен ли такой код

Код: Выделить всё
{$MODE OBJFPC}

type
  trec = record
    af,bf: Smallint;
  end;

procedure getab(rec: trec; var a,b);
begin
  Longint(a) := rec.af; Longint(b) := rec.bf
end;

const
  tst: trec = (af:1;bf:3);
var
  ta: Smallint;
  tb: Smallint;
begin
  getab(tst,ta,tb);
  writeln(ta,' ',tb)
end.


Если точнее мне надо, что бы процедура передавала через var аргументы значения Smallint любым целочисленным.

такой вариант точно неправилен, в чем я уже убедился.
Код: Выделить всё
{$MODE OBJFPC}

type
  trec = record
    af,bf: Smallint;
  end;

procedure getab(rec: trec; var a,b);
begin
  Smallint(a) := rec.af; Smallint(b) := rec.bf
end;

const
  tst: trec = (af:1;bf:3);
var
  ta: Longint = 100000;
  tb: Longint = 100000;
begin
  getab(tst,ta,tb);
  writeln(ta,' ',tb)
end.
trifon
постоялец
 
Сообщения: 135
Зарегистрирован: 24.12.2006 12:08:35

Сообщение Sergei I. Gorelkin » 20.02.2008 00:07:48

В Паскале нет понятия "любое целочисленное", в нем всегда указываются конкретные типы. При использовании нетипизированных параметров (а также Pointer) информация о типе теряется и ответственность за их соответствие переходит от компилятора к автору :)
Если передаешь smallint, а записываешь туда LongInt, значит, два соседних байта будут затерты. Если наоборот - два старших байта не запишутся.

Чтобы работало с разными типами, надо просто написать несколько перегруженных процедур - по одной на каждый нужный тип. Ну или использовать Variant, который сам в себе хранит свой тип...
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1405
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Максим » 20.02.2008 03:04:41

Что-то я не понял, чего сделать-то вообще надо? Зачем все эти сложности с типами?
Аватара пользователя
Максим
энтузиаст
 
Сообщения: 598
Зарегистрирован: 27.07.2007 01:51:43
Откуда: Москва

Сообщение trifon » 21.02.2008 15:00:41

Чего тут может быть непонято?
Есть процедура, берет два целочисленных var аргумента, содержащих любой мусор и помещает в них значения Smallint.
Во втором варианте кода в переменных оказывается мусор.
trifon
постоялец
 
Сообщения: 135
Зарегистрирован: 24.12.2006 12:08:35

Сообщение Максим » 22.02.2008 02:25:55

Да всё может быть непонятно. Мне вот кажется, что задачу вы поставили себе неверно, потому и сложности с типами возникли. Вот я и попросил уточнить.

Теперь по делу. Например, такой код у меня работает:
Код: Выделить всё
{$MODE OBJFPC}

type
  trec = record
    af,bf: Smallint;
  end;

procedure getab(rec: trec; var a,b: longint);
begin
  a := rec.af; b := rec.bf
end;

const
  tst: trec = (af:-32768;bf:3);
var
  ta: Longint = 100000;
  tb: Longint = 100000;
  tc: Smallint;
begin
  getab(tst,ta,tb);
  tc:= SmallInt(ta);
  writeln(tc,' ',tb)
end.

Но идеологически верный вариант - это, конечно, перегрузка функций.
Аватара пользователя
Максим
энтузиаст
 
Сообщения: 598
Зарегистрирован: 27.07.2007 01:51:43
Откуда: Москва

Сообщение trifon » 24.02.2008 23:53:59

Наверное первый вариант всё таки правильный.
Получается так - если аргументы меньше чем long, они приводятся к longint, а затем им присваиваются значения Smallint, что правильно, как я понимаю.
Да и компилятор не ругается, если заявлено в возможностях, то почему бы не воспользоваться этим.
Использовать четыре или более перегруженных вариантов не охота, потому что подобных процедур много и они декларируются в юните, слишком много лишнего кода.

Что касается предложенного варианта
Код: Выделить всё
procedure getab(rec: trec; var a,b: longint);

меняем в нём
Код: Выделить всё
  ta: Longint = 100000;
  tb: Longint = 100000;

на:
Код: Выделить всё
  ta: Smallint = 0;
  tb: Smallint = 0;

и получаем
Код: Выделить всё
Compiling test.pp
test.pp(20,18) Error: Call by var for arg no. 3 has to match exactly: Got "SmallInt" expected "LongInt"
test.pp(23,4) Fatal: There were 1 errors compiling module, stopping

Я несколько раз повторил, что getab должна брать любые целые(в пределах long), если не врубаемся, зачем в дурачков играть?
trifon
постоялец
 
Сообщения: 135
Зарегистрирован: 24.12.2006 12:08:35

Сообщение alexs » 25.02.2008 01:15:04

trifon
Используй оверлоадинг процедур
и используй строгую типизацию - в твоей задаче явно что-то не правильно спроектиовано.
Аватара пользователя
alexs
долгожитель
 
Сообщения: 4060
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь

Сообщение trifon » 25.02.2008 20:09:02

"Я чувствую, тут явно что то неправильно"
А можно поконкретнее, что неправильно - var аргументы или приведение целых друг к другу, а может еще что то?
В перегруженных процедурах их все равно придется приводить или они приведутся автоматом.

Если интересно зачем - заголовок для ncurses содержит макросы, извлекающие данные из структуры, естественно в макросах нет никаких понятий о типах, они просто подставляют в код значения.
Так вот мне нужен аналог данного макроса на free pascal.
Что в этой задаче неправильного?
И зачем тогда вообще нужны нетипизированные var аргументы?

Кстати в ocaml (имеет статическую типизацию), при объявлении переменной, указывать тип не обязательно и в большенстве случаев так и поступают, тип определяется при первом использовании по используемым функциям.
Последний раз редактировалось trifon 25.02.2008 21:41:25, всего редактировалось 1 раз.
trifon
постоялец
 
Сообщения: 135
Зарегистрирован: 24.12.2006 12:08:35

Сообщение Alexander » 25.02.2008 20:52:06

Может дашь оригинальный код на Си и люди скорее поймут ?
Некоторые здесь Си знают.
Аватара пользователя
Alexander
энтузиаст
 
Сообщения: 771
Зарегистрирован: 18.12.2005 19:10:00
Откуда: оттуда

Сообщение alexs » 25.02.2008 21:01:28

trifon писал(а):И зачем тогда вообще нужны нетипизированные var аргументы?

По большому счёту они вобще не нужны.
trifon писал(а):В перегруженных процедурах их все равно придется приводить или они приведутся автоматом.

На то они и перегруженные - ты пишеш процедуру для каждого из типов (Longint, Smalint) а при вызове компилятор сам разберётся по типу параметров какую процедуру вызвать.
Но опять таки, это хорошо для маленьких, вспомогательных утилит. И использовать это надо только понимая, что ты делаеш.
Аватара пользователя
alexs
долгожитель
 
Сообщения: 4060
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь

Сообщение trifon » 25.02.2008 21:12:47

Да без проблем
Код: Выделить всё

#define getattrs(win)      ((win)?(win)->_attrs:A_NORMAL)
#define getcurx(win)      ((win)?(win)->_curx:ERR)
#define getcury(win)      ((win)?(win)->_cury:ERR)
#define getbegx(win)      ((win)?(win)->_begx:ERR)
#define getbegy(win)      ((win)?(win)->_begy:ERR)
#define getmaxx(win)      ((win)?((win)->_maxx + 1):ERR)
#define getmaxy(win)      ((win)?((win)->_maxy + 1):ERR)
#define getparx(win)      ((win)?(win)->_parx:ERR)
#define getpary(win)      ((win)?(win)->_pary:ERR)

.......
#define getyx(win,y,x)      (y = getcury(win), x = getcurx(win))
#define getbegyx(win,y,x)   (y = getbegy(win), x = getbegx(win))
#define getmaxyx(win,y,x)   (y = getmaxy(win), x = getmaxx(win))
#define getparyx(win,y,x)   (y = getpary(win), x = getparx(win))

#define getsyx(y,x) do { if(newscr->_leaveok) (y)=(x)=-1; \
          else getyx(newscr,(y),(x)); \
          } while(0)
#define setsyx(y,x) do { if((y)==-1 && (x)==-1) newscr->_leaveok=TRUE; \
          else {newscr->_leaveok=FALSE;wmove(newscr,(y),(x));} \
          } while(0)


Кстати вариант с ошибкой, отправленный Attid на freepascal.org похоже принят, я не совсем в курсе что означает Assigned

В данном случае getyx является полным аналогом getab
Если getyx дать не нулевые Longint, можно получить мусор в ответ.
Второй вариант работает
Последний раз редактировалось trifon 25.02.2008 21:18:38, всего редактировалось 1 раз.
trifon
постоялец
 
Сообщения: 135
Зарегистрирован: 24.12.2006 12:08:35

Сообщение Максим » 25.02.2008 21:17:41

trifon писал(а):меняем в нём
Код: Выделить всё
  ta: Longint = 100000;
  tb: Longint = 100000;

на:
Код: Выделить всё
  ta: Smallint = 0;
  tb: Smallint = 0;

и получаем
Код: Выделить всё
Compiling test.pp
test.pp(20,18) Error: Call by var for arg no. 3 has to match exactly: Got "SmallInt" expected "LongInt"
test.pp(23,4) Fatal: There were 1 errors compiling module, stopping

Ну и приводите их при передаче в процедуру к Longint:
Код: Выделить всё
getab(tst,longint(ta),longint(tb));

:roll:
Аватара пользователя
Максим
энтузиаст
 
Сообщения: 598
Зарегистрирован: 27.07.2007 01:51:43
Откуда: Москва

Сообщение trifon » 25.02.2008 21:22:29

Ну и приводите их при передаче в процедуру к Longint:
Код: Выделить всё
getab(tst,longint(ta),longint(tb));

:roll:


Приводить придется во всех программах использующих данный юнит,
о существовании многих я могу и не знать, ибо не писал их
trifon
постоялец
 
Сообщения: 135
Зарегистрирован: 24.12.2006 12:08:35

Сообщение Максим » 25.02.2008 21:35:31

В этом случае проще использовать перегрузку функций. Ну можно ещё попробовать шаблоны (FPC не ниже 2.2.1).

Что касается приведённого кода на C, то это, насколько я могу судить, всего лишь довольно уродский способ извлечения данных из записи Win. При этом перед их извлечением производится проверка на её существование. Поэтому, по идее, типы должны определяться её содержимым.
Аватара пользователя
Максим
энтузиаст
 
Сообщения: 598
Зарегистрирован: 27.07.2007 01:51:43
Откуда: Москва

Сообщение Alexander » 25.02.2008 21:46:29

А что означает запись в скобках ? Значения по умолчанию, если
аргументы не заданы ?
Аватара пользователя
Alexander
энтузиаст
 
Сообщения: 771
Зарегистрирован: 18.12.2005 19:10:00
Откуда: оттуда

След.

Вернуться в Обучение Free Pascal

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 12

Рейтинг@Mail.ru