Размещение значения переменной в область памяти

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

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

Размещение значения переменной в область памяти

Сообщение bloodlines » 05.10.2009 14:02:22

Задача:
Есть указатель на некоторую область памяти
Код: Выделить всё
P:pointer;

Есть переменная
Код: Выделить всё
N:integer;

Допустим размер области памяти, на которую ссылается P, составляет 40 байт.
Вопрос: Как поместить значение переменной N в область памяти, на которую ссылается P причём не с самого начала области, а например с 5-го байта. Т.е. в области памяти должно получиться следующе:
1 - 4 байт - пусто
5 - (5+SizeOf(N))- значение переменной N
(5+SizeOf(N))-40 - пусто.
Можно ли это сделать средствами FreePascal?
Аватара пользователя
bloodlines
постоялец
 
Сообщения: 100
Зарегистрирован: 05.11.2008 11:26:19

Re: Размещение значения переменной в область памяти

Сообщение Mr.Smart » 05.10.2009 14:09:36

Используем адресную арифметику :wink:
Код: Выделить всё
PInteger(P+4)^:=N;
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!

Re: Размещение значения переменной в область памяти

Сообщение bloodlines » 05.10.2009 14:19:33

Спасибо!
Код: Выделить всё
PInteger
- это я так понимаю для типа Integer только. А для других типов, string, float?
Ещё один вопрос: Как сделать обратную операцию - прочитать из некоторой области памяти нужное количество байт и привести к нужному типу? Т.е. читаем SizeOf(N) байт. начиная с 5-го и приводим к типу integer. Для других типов данных то же интересует. (для простых типов - не массивов, записей, объектов и т.д.)
Аватара пользователя
bloodlines
постоялец
 
Сообщения: 100
Зарегистрирован: 05.11.2008 11:26:19

Re: Размещение значения переменной в область памяти

Сообщение Mr.Smart » 05.10.2009 14:51:01

PInteger это
Код: Выделить всё
type
  PInteger = ^Integer;

т.е. указатель на тип Integer. Для каждого простого есть подобные определения.
Типы String и записи к простым типам не относятся.
Для чтения записи переменных типа String:
Запись: подразумевается, что область данных уже выделена
Код: Выделить всё
  Move(S[1],P^,Length(S)); // S - строка, а P - указатель на заранее выделенный блок памяти

Чтение
Код: Выделить всё
  SetLength(S,Size); // Size - размер читаемого блока
  Move(P^,S1[1],Size); // P - указатель на память. S - строка

Для работы непосредственно с записями
Код: Выделить всё
type
  PTestRecord = ^TTestRecord;
  TTestRecord = packed record
    item: Integer;
    ...
  end;
.....
// Запись
  PTestRecord(P)^.item:=1;
// Чтение
  i:=PTestRecord(P)^.item;

или
Код: Выделить всё
var
  Rec: TTestRecord;
...
  Move(Rec,P^,SizeOf(Rec)); // копируем из Rec в P^

Классы и объекты по своей сути являются указателями на области памяти с определённой структурой. Т.е. в блок памяти можно сохранить указатель на класс, а не сам класс.
Код: Выделить всё
TMyClass(P+15).Method()


Добавлено спустя 4 минуты:
С массивами особых проблем нет.
1 способ:
Код: Выделить всё
type
  arr = array[0..15] of Integer;
  parr = ^arr;
....
  Parr(P+12)^[5]:=1;

2 способ простое копирование:
Код: Выделить всё
var arr: array[0..15] of Integer;
....
  Move((P+12)^,arr[0],SizeOf(arr));
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!

Re: Размещение значения переменной в область памяти

Сообщение bloodlines » 07.10.2009 09:45:56

Спасибо большое! Хотелось бы уточнить
Код: Выделить всё
PInteger(P+4)^:=N;

А как теперь из этой области памяти занести значение например в переменную M:integer; ?
Код: Выделить всё
Move(S[1],P^,Length(S));

Интересно, почему первым из параметров выступает первый символ строки S[1]?
И как поместить строку именно в произвольную область памяти, т.е. с 5-го байта и т.д.?
Аватара пользователя
bloodlines
постоялец
 
Сообщения: 100
Зарегистрирован: 05.11.2008 11:26:19

Re: Размещение значения переменной в область памяти

Сообщение Mr.Smart » 07.10.2009 09:57:17

bloodlines писал(а):А как теперь из этой области памяти занести значение например в переменную M:integer; ?

Код: Выделить всё
M:=PInteger(P+4)^

bloodlines писал(а):Интересно, почему первым из параметров выступает первый символ строки S[1]?
И как поместить строку именно в произвольную область памяти, т.е. с 5-го байта и т.д.?

Процедура Move определена следующим образом:
Код: Выделить всё
procedure Move(const source;var dest;count:SizeInt);

т.е. первый параметр source - откуда копировать, второй dest - куда, а третий count - соответственно количество байт.
Первый элемент строки именно S[1] т.к. это принято ещё со времён Н. Вирта :wink:
Если необходимо скопировать строку с 5-го байта указываем соответственно S[5] :wink:
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!

Re: Размещение значения переменной в область памяти

Сообщение bloodlines » 13.10.2009 09:37:46

А как насчёт такого варианта:
Есть переменные
Код: Выделить всё
Var
arr:array[1..18] of byte;
S:string;


Байты с 5-го по 12 массива arr заняты некоторым значением (например типа Float, Float если я правильно помню занимает 8 байт). Как в переменную S занести значение определённое с 5-го по 12 байт массива arr? Интересуют варианты и для других типов кроме float (string (при условии что знаем длину строки), integer, datetime ), но все нужно заносить в переменную S.
Аватара пользователя
bloodlines
постоялец
 
Сообщения: 100
Зарегистрирован: 05.11.2008 11:26:19

Re: Размещение значения переменной в область памяти

Сообщение Mr.Smart » 13.10.2009 09:47:11

bloodlines писал(а):... Float если я правильно помню занимает 8 байт...

В спецификации Паскаля нет такого типа, но если вы имеете ввиду Си/Си++ то тип float - 4 байта, а 8 байт это размерность типа double.

А смысл в строку помещать данные не относящиеся к символам? Или вы хотите что бы данные преобразовывались с начало в строковый вид?
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!

Re: Размещение значения переменной в область памяти

Сообщение bloodlines » 13.10.2009 09:56:19

а 8 байт это размерность типа double.
Точно, забыл совсем :) .
Код: Выделить всё
А смысл в строку помещать данные не относящиеся к символам? Или вы хотите что бы данные преобразовывались с начало в строковый вид?

Именно так! Сначала мне необходим строковый вид.
Аватара пользователя
bloodlines
постоялец
 
Сообщения: 100
Зарегистрирован: 05.11.2008 11:26:19

Re: Размещение значения переменной в область памяти

Сообщение Mr.Smart » 13.10.2009 10:05:48

Простейший вариант преобразовываем в строку и помещаем куда нужно:
Код: Выделить всё
...
s:=FloatToStr(PDouble(@arr[8])^);
...
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!

Re: Размещение значения переменной в область памяти

Сообщение bloodlines » 13.10.2009 11:00:08

Код: Выделить всё
Простейший вариант

Я конечно извиняюсь, но такая постановка вопроса заставляет поинтересоваться о других (сложных) вариантах.
А для приведения к строковому типу обязательно знать к какому типу относятся нужный набор байт в массиве?

Добавлено спустя 23 часа 21 минуту 38 секунд:
разбирался, экспериментировал...
Вот этот код работает
Код: Выделить всё
Var
  arr:BufArr;
  PArr:PBufArr;
  n,m:integer;

SetLength(arr, 4);
  Parr:=@arr;
  n:=10;
  PInteger(Parr)^:=n;
  m:=PInteger(Parr)^;
  ShowMessage(IntToStr(m));


В переменной m действительно оказывается значение 10.
А вот этот код
Код: Выделить всё
Var
  arr:BufArr;
  PArr:PBufArr;
  n,m:integer;

SetLength(arr, 20);
  Parr:=@arr;
  n:=10;
  PInteger(Parr+4)^:=n;
  m:=PInteger(Parr+4)^;
  ShowMessage(IntToStr(m));


Вызывает ошибку в стоке
Код: Выделить всё
m:=PInteger(Parr+4)^;

В чём ошибка? Подскажите пожалуйста!
Аватара пользователя
bloodlines
постоялец
 
Сообщения: 100
Зарегистрирован: 05.11.2008 11:26:19


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

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

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

Рейтинг@Mail.ru