Страница 1 из 2

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

СообщениеДобавлено: 19.02.2008 23:43:35
trifon
корректен ли такой код

Код: Выделить всё
{$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.

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

Чтобы работало с разными типами, надо просто написать несколько перегруженных процедур - по одной на каждый нужный тип. Ну или использовать Variant, который сам в себе хранит свой тип...

СообщениеДобавлено: 20.02.2008 03:04:41
Максим
Что-то я не понял, чего сделать-то вообще надо? Зачем все эти сложности с типами?

СообщениеДобавлено: 21.02.2008 15:00:41
trifon
Чего тут может быть непонято?
Есть процедура, берет два целочисленных var аргумента, содержащих любой мусор и помещает в них значения Smallint.
Во втором варианте кода в переменных оказывается мусор.

СообщениеДобавлено: 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.

Но идеологически верный вариант - это, конечно, перегрузка функций.

СообщениеДобавлено: 24.02.2008 23:53:59
trifon
Наверное первый вариант всё таки правильный.
Получается так - если аргументы меньше чем 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), если не врубаемся, зачем в дурачков играть?

СообщениеДобавлено: 25.02.2008 01:15:04
alexs
trifon
Используй оверлоадинг процедур
и используй строгую типизацию - в твоей задаче явно что-то не правильно спроектиовано.

СообщениеДобавлено: 25.02.2008 20:09:02
trifon
"Я чувствую, тут явно что то неправильно"
А можно поконкретнее, что неправильно - var аргументы или приведение целых друг к другу, а может еще что то?
В перегруженных процедурах их все равно придется приводить или они приведутся автоматом.

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

Кстати в ocaml (имеет статическую типизацию), при объявлении переменной, указывать тип не обязательно и в большенстве случаев так и поступают, тип определяется при первом использовании по используемым функциям.

СообщениеДобавлено: 25.02.2008 20:52:06
Alexander
Может дашь оригинальный код на Си и люди скорее поймут ?
Некоторые здесь Си знают.

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

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

На то они и перегруженные - ты пишеш процедуру для каждого из типов (Longint, Smalint) а при вызове компилятор сам разберётся по типу параметров какую процедуру вызвать.
Но опять таки, это хорошо для маленьких, вспомогательных утилит. И использовать это надо только понимая, что ты делаеш.

СообщениеДобавлено: 25.02.2008 21:12:47
trifon
Да без проблем
Код: Выделить всё

#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, можно получить мусор в ответ.
Второй вариант работает

СообщениеДобавлено: 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:

СообщениеДобавлено: 25.02.2008 21:22:29
trifon
Ну и приводите их при передаче в процедуру к Longint:
Код: Выделить всё
getab(tst,longint(ta),longint(tb));

:roll:


Приводить придется во всех программах использующих данный юнит,
о существовании многих я могу и не знать, ибо не писал их

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

Что касается приведённого кода на C, то это, насколько я могу судить, всего лишь довольно уродский способ извлечения данных из записи Win. При этом перед их извлечением производится проверка на её существование. Поэтому, по идее, типы должны определяться её содержимым.

СообщениеДобавлено: 25.02.2008 21:46:29
Alexander
А что означает запись в скобках ? Значения по умолчанию, если
аргументы не заданы ?