истинный смысл "Conversion between ordinals and pointers is

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

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

истинный смысл "Conversion between ordinals and pointers is

Сообщение Cheb » 13.03.2020 23:21:54

Истинный смысл "Conversion between ordinals and pointers is not portable" - "Ты дятел, оно у тебя приводится к 32-битным интам при вычислении" / "Проверь свои кривые тайп-касты, там где-то неэкранированный longint затесался и всё распидорашивает"

Настоящие джедаи документацию не читают, ога... :x

Ну, теперь я знаю,
а) почему я - дятел
б) почему мой движок упорно крашился, если собирать под x86-64

Рукожопие:
Код: Выделить всё
f_Size: longint
[...]
function TChepersyMemoryManagerChunk.Alloc: pointer;
var
  i, k: integer;
[...]
  Exit(pointer(ptruint(Self) + ptruint(k) * f_Size));


ТруЪ:
Код: Выделить всё
Exit(pointer(ptruint(Self) + ptruint(k * f_Size)));


см. тж.
https://www.pascalgamedevelopment.com/s ... post149449
https://bugs.freepascal.org/view.php?id=36792
Аватара пользователя
Cheb
энтузиаст
 
Сообщения: 994
Зарегистрирован: 06.06.2005 15:54:34

Re: истинный смысл "Conversion between ordinals and pointers

Сообщение Дож » 14.03.2020 13:19:40

Зачем так сложно, когда можно так?
Код: Выделить всё
Exit(Pointer(Self) + k * f_Size);
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

Re: истинный смысл "Conversion between ordinals and pointers

Сообщение Cheb » 14.03.2020 15:53:44

Эээ...
Эээээ?..
То есть, когда к *указателю* прибавляешь longint, вычисления автоматически идут в пространстве указателя?..
Естественно же.

Надо подумать, почему я так не делаю. Подозреваю - дурная привычка, появившаяся из-за каких-то вывихов {$mode delphi} в fpc 1.1 и нативного Дельфи 4. Я давно переключился на {$mode objfpc}, а привычка заворачивать всё в тайпкасты осталась.
Аватара пользователя
Cheb
энтузиаст
 
Сообщения: 994
Зарегистрирован: 06.06.2005 15:54:34

Re: истинный смысл "Conversion between ordinals and pointers

Сообщение Awkward » 14.03.2020 16:47:29

главное, не забудь, что если указатель типизированный, увеличение его может быть не в байтах, а единицах его типа.
Awkward
новенький
 
Сообщения: 43
Зарегистрирован: 19.01.2017 00:06:47

Re: истинный смысл "Conversion between ordinals and pointers

Сообщение Cheb » 14.03.2020 17:40:48

Ну, дык.

Почему же я привык их к целому приводить для арифметики?
ЕМНИП, ранние Дельфи (2, 4, 6) не разрешали арифметику с указателями, вынуждая кастовать в cardinal и обратно.
Аватара пользователя
Cheb
энтузиаст
 
Сообщения: 994
Зарегистрирован: 06.06.2005 15:54:34

Re: истинный смысл "Conversion between ordinals and pointers

Сообщение Awkward » 14.03.2020 18:42:18

хзхз, я сидел на дельфи 5 очень долго, арифметика с указателями когда была нужна, просто приводил к типу Pchar (PAnsiChar)
Awkward
новенький
 
Сообщения: 43
Зарегистрирован: 19.01.2017 00:06:47

Re: истинный смысл "Conversion between ordinals and pointers

Сообщение скалогрыз » 15.03.2020 07:59:44

Cheb писал(а):Рукожопие:
ТруЪ:

вообще не убедительно.

1х "Conversion between ordinals and pointers is not portable" в твоём случае это не Warning, а Hint.
а значит ошибки нет. Единственное чем ты рескуешь, это что такой код, под какой-нить JVM не скомпилируется. (но ты же не хочешь в JVM? ;) )

2х исходя из твоего фикса, ты утверждаешь, что при перемножении 64-битного на 32-битное, результат будет 32-битный? или как?
почему приведение результата умножения (k * f_Size) к 64-битному решает какие-то проблемы?!

Вывод.
- или ты подкрутил что-то в другом месте, что движок перестал крашится
- или движок всё ещё крашится по фазе луны.

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

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}
  cthreads,
  {$ENDIF}
  Classes
  { you can add units after this };

type
  TMyObject = class(TObject)
  public
    k : integer;
    f_size : integer;
    function Alloc: Pointer;
    function Alloc2: Pointer;
  end;

function TMyObject.Alloc: Pointer;
begin
  Result:=(pointer(ptruint(Self) + ptruint(k) * f_Size));
end;


function TMyObject.Alloc2: Pointer;
begin
  Result:=(pointer(ptruint(Self) + ptruint(k * f_Size)));
end;

var
  m : TMyObject;
begin
  m := TMyObject.Create;
  m.k := MaxInt;
  m.f_size:=MaxInt;
  writeln(sizeof(pointer));
  writeln(PtrUInt(m.Alloc));
  writeln(PtrUInt(m.Alloc2));
end.
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: истинный смысл "Conversion between ordinals and pointers

Сообщение Cheb » 15.03.2020 12:59:33

в твоём случае это не Warning, а Hint.

в твоём случае это не Warning, а Hint.
Нет. Стопроцентный warning (подсвечено жёлтым, я науськал MSEIde выделять хинты зелёным а вонинги жёлтым).
(я использую фпц 2.6.4 для сборки 32-битной версии и 3.1.1 для сборки 64-битной)

исходя из твоего фикса, ты утверждаешь, что при перемножении 64-битного на 32-битное, результат будет 32-битный?

ЕМНИП, Паскаль при операциях с целыми берёт наименьшую разрядность из двух операндов - так сложилось исторически. Поэтому надо кастовать мЕньший операнд к бОльшему, чтобы не получить на выходе тыкву.
В случае (k * f_Size) само умножение - пофиг, там не бывает больше 128К, но потом надо это значение скастовать к 64-битному, чтобы не порезало операцию сложения.
Потом мне говорят: если первый операнд - PByte, то ничего не порежет. а, наоборот, расширит до разрядности указателя.

Твой пример - лажа, там переполнения в умножении прут и всё развозит (оба результата одинаковые, но ОБА некорректные).
Причём, проверять надо не какой Self на душу положит, а большой указатель > $ffffffff, причём, собирая под 64 бита.

Но... Что самое смешное - все варианты работают корректно. Даже (pointer(ptruint(bigptr) + k * f_Size));

ИЧСХ, вонинги прут только при сборке под 32 бита. Кросс-компилятор x64 в этих местах молчит.
Код: Выделить всё
program project1;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}
  cthreads,
  {$ENDIF}
  sysutils,
  Classes
  { you can add units after this };
  {$rangechecks on}
  {$overflowchecks on}

type
  TMyObject = class(TObject)
  public
    k, f_size : longint;
    bigptr: pointer;
    function Alloc: Pointer;
    function Alloc2: Pointer;
  end;

function TMyObject.Alloc: Pointer;
begin
  Result:=(pointer(ptruint(bigptr) + k * f_Size));
end;


function TMyObject.Alloc2: Pointer;
begin
  Result:=(pointer(ptruint(bigptr) + ptruint(k * f_Size)));
end;

var
  m : TMyObject;
begin
  m := TMyObject.Create;
  m.bigptr:= pointer({$ifdef cpu64}$100000000{$else}$400000{$endif});
  m.k := 2;
  m.f_size:= 2;
  writeln(sizeof(pointer));
  writeln(IntToHex(PtrUInt(m.bigptr), 16));
  writeln(IntToHex(PtrUInt(m.Alloc), 16));
  writeln(IntToHex(PtrUInt(m.Alloc2), 16));
end.


d:\stuff\tmp>c:\fpc\2.6.4\bin\i386-win32\ppcrossx64 -Twin64 project1.pas
Free Pascal Compiler version 2.6.4 [2014/03/06] for x86_64
Copyright (c) 1993-2014 by Florian Klaempfl and others
Target OS: Win64 for x64
Compiling project1.pas
Linking project1.exe
45 lines compiled, 0.2 sec , 174528 bytes code, 42852 bytes data

d:\stuff\tmp>project1
8
0000000100000000
0000000100000004
0000000100000004
Аватара пользователя
Cheb
энтузиаст
 
Сообщения: 994
Зарегистрирован: 06.06.2005 15:54:34

Re: истинный смысл "Conversion between ordinals and pointers

Сообщение скалогрыз » 15.03.2020 17:57:17

Cheb писал(а):Твой пример - лажа, там переполнения в умножении прут и всё развозит (оба результата одинаковые, но ОБА некорректные)

не вопрос - лажа!
но какие нужно присовить значения k и f_size чтобы Alloc и Alloc2 стали возвращать разные значения?!

Cheb писал(а):ЕМНИП, Паскаль при операциях с целыми берёт наименьшую разрядность из двух операндов - так сложилось исторически

я не думаю, что так работает хоть какой-либо из компиляторов. иначе при сложении 256+1, у тебя всегда в итоге будет 1! (а не 257)

если верить официально документации: https://www.freepascal.org/docs-html/cu ... 250003.1.1
то:
As a pascal compiler, Free Pascal does automatic type conversion and upgrading in expressions where different kinds of integer types are used:
1) Every platform has a ”native” integer size, depending on whether the platform is 8-bit, 16-bit, 32-bit or 64-bit. e.g. On AVR this is 8-bit.
2) Every integer smaller than the ”native” size is promoted to a signed version of the ”native” size. Integers equal to the ”native” size keep their signedness.
3) The result of binary arithmetic operators (+, -, *, etc.) is determined in the following way:
a. If at least one of the operands is larger than the native integer size, the result is chosen to be the smallest type that encompasses the ranges of the types of both operands. This means that mixing an unsigned with a smaller or equal in size signed will produce a signed type that is larger than both of them.
b. If both operands have the same signedness, the result is the same type as them. The only exception is subtracting (-): in the case of unsigned-unsigned subtracting produces a signed result in FPC (as in Delphi, but not in TP7).
c. Mixing signed and unsigned operands of the ”native” int size produces a larger signed result. This means that mixing longint and longword on 32-bit platforms will produce an int64. Similarly, mixing byte and shortint on 8-bit platforms (AVR) will produce a smallint.


так что я всё ещё не вижу причин, чтобы у тебя на 64 битке падало.
кстати! с какой ошибкой краш происходил?

Cheb писал(а):ИЧСХ, вонинги прут только при сборке под 32 бита. Кросс-компилятор x64 в этих местах молчит.

Потому что они там хинты?
добавь:
-vewnhibq

к командной строке компиляции
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: истинный смысл "Conversion between ordinals and pointers

Сообщение runewalsh » 15.03.2020 18:43:56

Ни в одной версии кода нет проблемы.
Cheb писал(а):ИЧСХ, вонинги прут только при сборке под 32 бита. Кросс-компилятор x64 в этих местах молчит.

Ворнинг вместо хинта будет, если ты кастуешь указатель к целому типу НЕ ТОГО ЖЕ РАЗМЕРА. Может быть, ты используешь самодельный PtrUint вместо System.PtrUint?
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 578
Зарегистрирован: 27.04.2010 00:15:25

Re: истинный смысл "Conversion between ordinals and pointers

Сообщение Cheb » 15.03.2020 19:05:00

Я понял! Изображение
На 32-битной платформе компилятор наоборот расширяет вычисления до 64-битных а потом урезает до указателя, и это кажется ему стрёмным!

Добавлено спустя 17 минут 11 секунд:
Re: истинный смысл "Conversion between ordinals and pointers is
кстати! с какой ошибкой краш происходил?

Перемежающиеся мутные AV в непонятных местах, часто - в коде, для которого нет информации о строках. Иногда - каскады исключений при выходе, когда весь мой код уже завершился.

Может быть, ты используешь самодельный PtrUint

Когда-то было, в jedi_directsound8.pp PtrUInt = Longword;
Сейчас давно закомментировано, с очень прочувствованным матерным примечанием.
Аватара пользователя
Cheb
энтузиаст
 
Сообщения: 994
Зарегистрирован: 06.06.2005 15:54:34

Re: истинный смысл "Conversion between ordinals and pointers

Сообщение скалогрыз » 15.03.2020 19:33:58

Cheb писал(а):Перемежающиеся мутные AV в непонятных местах

и после того как ты вынес умножение внутрь тайпкаста они все исчели?

(хотя указатель возвращался один и тот же, что до изменения, что после?!)

если у тебя всё ещё ворнинг в твоём проекте, тебе нужно проверить, а где ещё ptruint может быть объявлен.
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: истинный смысл "Conversion between ordinals and pointers

Сообщение Cheb » 15.03.2020 21:45:58

Я с той поры столько выполол, особенно после того, как наступил на горло своей песне и отказался от принципа "настоящие джедаи не пользуются проверками диапазона/переполнения". Тогда столько ужасов вылезло...

Давно уже не падало - но я и всерьёз х64 версию не проверял после великого перетряха. 2018-2020 годов
Аватара пользователя
Cheb
энтузиаст
 
Сообщения: 994
Зарегистрирован: 06.06.2005 15:54:34


Вернуться в Free Pascal Compiler

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

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

Рейтинг@Mail.ru