Conversion between ordinals and pointers is not portable

Вопросы программирования на Free Pascal, использования компилятора и утилит.

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

Flanter
новенький
Сообщения: 42
Зарегистрирован: 03.11.2007 21:15:54

Conversion between ordinals and pointers is not portable

Сообщение Flanter »

Вообще, тема, конечно, относится к Lazarus'у, но суть всё-таки ближе к общему программированию. Дело в том, что часто бывает нужно передать числовые данные в поле типа "указатель". Например, в случае дерева (TTreeView) создаю ветку (TTreeNode) и путём явного преобразования навешиваю ей данные:

Код: Выделить всё

Node.Data := TObject(17);

Компилятор, естественно, ругается:

Код: Выделить всё

Hint: Conversion between ordinals and pointers is not portable

Или, при обратном преобразовании:

Код: Выделить всё

if Integer(Node.Data) = 17 then

получаем уже предупреждение:

Код: Выделить всё

Warning: Converting pointers to signed integers may result in wrong comparison results and range errors, use an unsigned type instead.

Собственно, вопрос: как вообще правильно передавать числовые данные через указатель? Выделять память, заносить туда число и присваивать указатель? Как-то громоздко получается, да и дополнительно потом отслеживать придётся при разрушении основного объекта, чтобы утечек не было...

Ну, или хотя бы, как отключить данные Warning и Hint? Хотя, конечно, хотелось бы разобраться в сути...

P.S. Прошу прощения за ламерский вопрос :roll:
Аватара пользователя
Дож
энтузиаст
Сообщения: 900
Зарегистрирован: 12.10.2008 16:14:47

Сообщение Дож »

Код: Выделить всё

// Node.Data имеет тип Pointer
Node.Data := Pointer(17);
if Cardinal(Node.Data) = 17 then

Чем не решение?
Flanter
новенький
Сообщения: 42
Зарегистрирован: 03.11.2007 21:15:54

Сообщение Flanter »

На

Код: Выделить всё

if Cardinal(Node.Data) = 17 then

точно так же ругается... Там проблема, как я понимаю, в том, что такой код не будет нормально компилироваться 64-битным компилятором, ведь указатели там будут тоже 64-разрядные (а Integer и Cardinal 32-разрядные, только одно знаковое, а другое - беззнаковое). Меняю Integer на Int64 или UInt64 - то же самое, только Hint превращается в Warning...
Аватара пользователя
XProger
новенький
Сообщения: 44
Зарегистрирован: 13.08.2007 02:52:28
Откуда: Москва
Контактная информация:

Сообщение XProger »

Код: Выделить всё

var
  p : PAnsiChar;
begin
  p := nil;
  Node.Data := TObject(@p[17]);
...
end;

Ничего умнее придумать не смог, а хинты и нотисы отключаются убиранием -viewnh из командной строки компилятору )
Flanter
новенький
Сообщения: 42
Зарегистрирован: 03.11.2007 21:15:54

Сообщение Flanter »

Ну, с преобразованием Integer -> Pointer ещё как-то более-менее понятно, но вот с обратным преобразованием - идей у меня нет. Пока сделал две спец. функции для преобразования:

Код: Выделить всё

function ToPtr(I: PtrInt): Pointer; inline;
begin
{$HINTS OFF}
  Result := Pointer(I);
{$HINTS ON}
end;

function ToInt(P: Pointer): PtrInt; inline;
begin
{$HINTS OFF}
  Result := PtrInt(P);
{$HINTS ON}
end;

Тип используется PtrInt, он по размеру всегда эквивалентен указателю, хотя есть ли в этом смысл пока не очень ясно...

Все хинты отключать не хочется, т.к. бывают и полезные :)
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
Сообщения: 1409
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Sergei I. Gorelkin »

Недавно в компилятор добавили возможность избирательно управлять сообщениями, в частности, отключать ненужные хинты.
Flanter
новенький
Сообщения: 42
Зарегистрирован: 03.11.2007 21:15:54

Сообщение Flanter »

А это уже в 2.2.2 есть, или только в ночных сборках? Вроде в списке изменений 2.2.2 нету этого...

Вот опять же, раз уж про это речь зашла, в компиляторе теперь можно будет отключать отдельно сообщения о неиспользуемых переменных в var и отдельно сообщения о неиспользуемых параметрах функции/процедуры? Delphi вроде не сообщает, если я в процедуре не использую какие-то параметры, а FreePascal на каждый такой случай ругается хинтом...

Или, может, это тоже есть, просто я не нашёл опцию? В Lazarus IDE это можно отключить, но только для параметра Sender...
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
Сообщения: 1409
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Sergei I. Gorelkin »

Это ключи командной строки -vq, -vm. После -vm указываются через запятую номера сообщений, которые нужно задавить. И, кажется, после каждого номера может быть еще и буква, позволяющая его не только задавить, но и, например, сделать ошибкой. Для выяснения нужных номеров используется -vq.
Скорее всего, в 2.2.2 оно не попало.
SAK
постоялец
Сообщения: 158
Зарегистрирован: 17.02.2006 23:45:14
Откуда: Тим
Контактная информация:

Сообщение SAK »

Можно избавиться от сообщений объявив node.data как запись с вариантами.

Код: Выделить всё

  TNode = record
    //......
    case byte of
     1: (DataInt: Integer);
     2: (DataPtr: Pointer)
   end;

Или если TNode - объект или класс, то:

Код: Выделить всё

TData = record
    case byte of
     1: (AsInt: Integer);
     2: (AsPtr: Pointer)
   end;

TNode = Class
  //.....
  Data: TData;
end;

Тогда получаем:

Код: Выделить всё

if Node.Data.AsInt = 17 then
Flanter
новенький
Сообщения: 42
Зарегистрирован: 03.11.2007 21:15:54

Сообщение Flanter »

Не, если бы это зависело от меня, то я, конечно, в своей программе объявил бы Data вообще как Integer :) Но увы, Node - это экземпляр класса TTreeNode, который является частью библиотеки Lazarus LCL, поэтому приходится искать пути обхода.
svk12
постоялец
Сообщения: 411
Зарегистрирован: 09.06.2008 18:42:47

Сообщение svk12 »

var
PData:Pointer;

GetMem(Pdata,SizeOf(integer));
Pdata^:=17;
Node.Data:=PData;
if integer(PData^)=17 then...
Flanter
новенький
Сообщения: 42
Зарегистрирован: 03.11.2007 21:15:54

Сообщение Flanter »

В принципе, да - такой вариант самый правильный. Я знал, что всё им и закончится :)

Ну что делать - придётся дописывать ещё код для освобождения памяти при каждом разрушении сотни объектов Node...
SAK
постоялец
Сообщения: 158
Зарегистрирован: 17.02.2006 23:45:14
Откуда: Тим
Контактная информация:

Сообщение SAK »

Flanter писал(а):Node - это экземпляр класса TTreeNode

Тогда:

Код: Выделить всё

if (p-pchar(0))=17 then

Компилятор ошибок не видит, оптимизатор выбросит лишние операции :)
По крайней мере у меня ничего не пишет по этому поводу.
Flanter
новенький
Сообщения: 42
Зарегистрирован: 03.11.2007 21:15:54

Сообщение Flanter »

А подниму-ка я старую тему :)

В новом Lazarus'е (0.9.28[.2]) в опциях проекта есть закладка Messages, которая позволяет отключать отдельные сообщения (опция -vm, о которой говорил Сергей Горелкин). А нет ли соответствующей директивы компилятора? Нынешние {$HINTS OFF} и {$HINTS ON} воздействуют на все подсказки, а вот чтобы конкретную вырубить? То ли я плохо искал, то ли нет её, не нашёл, в общем...

Нужно это бывает в том случае, если один модуль, генерирующих конкретный хинт, используется в нескольких проектах. Тогда отключать этот хинт приходится в свойствах каждого проекта. А так вставил бы в начало директиву - и нет проблем...
MageSlayer
постоялец
Сообщения: 216
Зарегистрирован: 07.09.2006 12:30:44

Сообщение MageSlayer »

Собственно тип PtrInt, объявленный в system, для этого и предназначен.
Ответить