Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Указатели [D7, WinXP]


compiller ©   (2007-01-12 18:59:00) 

Здравствуйте. У меня несколько вопросов по указателям:
1) При получении указателя на элемент массива извне все работает нормально, в примере 2, p содержит неправильное значение.

Пример 1:
P := @MyObject.Items[0]; // Возвращает реальный указатель

Пример 2:
function TMyObject.AddItem;
begin
SetLength(Items, Length(Items)+1);
Items[High(Items)] := TMyItem.Create;

P := @Items[0]; // Возвращает неправильное значение
end;

При вызове функции значение p иногда изменяется, а иногда нет! Я не могу понять из за чего это происходит. Может баг в delphi, или это у меня руки кривые?

2) Почему, если использовать прототип 1, то значение в eax больше реального на 4?

// Прототип функции
1) function PtrAdd(const P; X: Integer): Pointer;
2) function PtrAdd(P: Pointer; X: Integer): Pointer;

// Код функции
asm
mov  eax,P
mov  edx,[X]
add  eax,edx
mov  Result,eax
end;


evvcom   (2007-01-22 15:15:00) [1]

> [2] ors_archangel ©   (13.01.07 17:44)
> Потому что const - это передача по ссылке (в данном случае
> и чаще всего), т.е. передаётся не значение указателя, а
> ссылка на этот указатель

Передается в любом случае 4 байтовое значение. В данном случае передается именно значение указателя. Вот с var-ом передался бы указатель на этот Pointer. Я смотрел как-то передачу array[0..N] of Byte (Char). Если N<=3, то передается массив "значением", т.е. одним 4-х байтовым значением, иначе указатель на 0-й символ.


Ega23   (2007-01-22 14:45:00) [2]


> Что -то такое делал. Зачем не помню.
>


Передача callback-адреса?


tesseract   (2007-01-22 12:10:00) [3]


>> нельзя складывать укзатели
> и это правильно ) просто в этом нет никакого смысла ))


Иногда есть. Вроде так должно сработать

myaddr:=Cardinal(@MyPointer);

Что -то такое делал. Зачем не помню.


Eraser   (2007-01-22 01:06:00) [4]

> [5] ors_archangel ©   (13.01.07 20:11)


> нельзя складывать укзатели

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

> [0] compiller   (12.01.07 18:59)

что такое Items ?


compiller   (2007-01-21 23:40:00) [5]


> DevilDevil ©   (13.01.07 16:45) [1]


Функция не принадлежт классу.

С этим уже разобрался.


> ors_archangel ©   (13.01.07 17:44) [2]


P, глобальная переменная. Весь прикол в том, что если присваивать значение P из класса в котором содержится Items, то при обращении по адресу P, вылетает raise

Спасибо за помощь


ors_archangel   (2007-01-13 20:37:00) [6]


> DevilDevil ©   (13.01.07 20:29) [6]

Я сразу так и подумал, что ты Си вспомнил :)
Inc - кстати, хорошее решение, ну а с PChar, кстати, можно даже так писать

 p + 2;

- прибавит 2 (именно 2, потому что sizeof(char)=1) к p (если {$x+}), - единственый случай, когда операция '+' может не возвращать значения :)


DevilDevil   (2007-01-13 20:29:00) [7]

Мда, действительно ошибся... но ошибся небеспочвенно:

1) Над указателями в Си действует оператор "+".
2) p1 увеличится на 10:
procedure TForm1.FormCreate(Sender: TObject);
var
 p1, p2 : pword;
begin
 p1 := @Self;
 Inc(p1, 5);
end;


ors_archangel   (2007-01-13 20:11:00) [8]


> Такие шутки прокатывают абсолютно со всеми указателями

Пример кода, в котором p1,p2: pointer, x: integer, и который будет хотя бы компилироваться, пожалуйста, если не сложно (компилироваться в Delphi7!). Извини, но ты не прав: не существует оператора '+', который мог бы оперировать с указательными типами: нельзя складывать укзатели, нельзя к указателю прибавить любой другой тип, для указателей существуют только оператор разымёнывания '^'. Почему все пишут, допустим

 PDword(integer(p)+8)^,

а не "проще и понятнее":

 PDword(p+8)^.

Но это, как я сказал в [3], не относится к типу PChar, если расширенный синтаксис включен {$x+}, если выключён, то даже

 p2 := pchar(p) + x;

не будет не то что работать, но даже компилироваться, это и есть строгая типизация в понимании Паскаля. Попробуй, если не веришь


DevilDevil   (2007-01-13 18:03:00) [9]


> В нереальных, но существующих условиях делать это даст только
> operator, который not applicable to this operand type. Такие
> штуки могут прокатывать только с PChar:
>
>  p2 := pchar(p1) + x;


Такие шутки прокатывают абсолютно со всеми указателями


ors_archangel   (2007-01-13 17:50:00) [10]


DevilDevil ©   (13.01.07 16:45) [1]
>  динамичесикий массив может "оказаться" в другой области
> памяти, это не из-за Delphi, а из-за Винды, точнее из-за
> особенности оперативной памяти.

Ещё точнее это из-за особенностей менеджера памяти каждой Delphi-программы

> в реальных условиях и проще и понятнее делать так:
> P2 := pbyte(P1) + X;

В нереальных, но существующих условиях делать это даст только operator, который not applicable to this operand type. Такие штуки могут прокатывать только с PChar:

 p2 := pchar(p1) + x;


ors_archangel   (2007-01-13 17:44:00) [11]

2 compiler
1

> P := @Items[0]; // Возвращает неправильное значение

Кто возвращает?
Что значит неправильное значение?
  А что нужно?
Что такое P?
Это глобальная переменная?
 Зачем ты её меняешь в методе класса?
2

>  Почему … значение в eax больше реального на 4?

Потому что const - это передача по ссылке (в данном случае и чаще всего), т.е. передаётся не значение указателя, а ссылка на этот указатель, например указатель расположен в стеке по адресу [esp+offs] и указывает на что-то с адрессом $00aabbcc, тогда в 1) передаётся esp+offs, а во 2) передаётся $00aabbcc


DevilDevil   (2007-01-13 16:45:00) [12]

1) Указатель в обоих случаях верен. Другое дело, что при изменении размерности динамического массива происходит перераспределение занимаемоё памяти, вследствие чего весь динамичесикий массив может "оказаться" в другой области памяти, это не из-за Delphi, а из-за Винды, точнее из-за особенности оперативной памяти.

2) а) у тебя просто функция или функция класса? Это принципиально важно
   б) зачем тебе использовать ассемблер?
   в) если это просто функция, то: P === eax, X === edx, в качестве результирующего значения Result использовать не надо, результат оставь в eax:
  function PtrAdd(P: Pointer; X: Integer): Pointer;
  asm
     add eax, edx
  end;  

   г) в реальных условиях и проще и понятнее делать так:
P2 := pbyte(P1) + X;
   д) ну а если .... незнаю как написать, пистаь не буду ;)

P.S. незабудь сказать спасибо ;)


Наверх

Титульная страница Поиск, карта сайта Написать письмо