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

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

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

Ответить
Аватара пользователя
bloodlines
постоялец
Сообщения: 100
Зарегистрирован: 05.11.2008 10:26:19

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

Сообщение bloodlines »

Задача:
Есть указатель на некоторую область памяти

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

P:pointer;

Есть переменная

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

N:integer;

Допустим размер области памяти, на которую ссылается P, составляет 40 байт.
Вопрос: Как поместить значение переменной N в область памяти, на которую ссылается P причём не с самого начала области, а например с 5-го байта. Т.е. в области памяти должно получиться следующе:
1 - 4 байт - пусто
5 - (5+SizeOf(N))- значение переменной N
(5+SizeOf(N))-40 - пусто.
Можно ли это сделать средствами FreePascal?
Mr.Smart
долгожитель
Сообщения: 1796
Зарегистрирован: 29.03.2008 00:01:11
Откуда: из леса!

Сообщение Mr.Smart »

Используем адресную арифметику :wink:

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

PInteger(P+4)^:=N;
Аватара пользователя
bloodlines
постоялец
Сообщения: 100
Зарегистрирован: 05.11.2008 10:26:19

Сообщение bloodlines »

Спасибо!

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

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

Сообщение Mr.Smart »

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));
Аватара пользователя
bloodlines
постоялец
Сообщения: 100
Зарегистрирован: 05.11.2008 10:26:19

Сообщение bloodlines »

Спасибо большое! Хотелось бы уточнить

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

PInteger(P+4)^:=N;

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

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

Move(S[1],P^,Length(S));

Интересно, почему первым из параметров выступает первый символ строки S[1]?
И как поместить строку именно в произвольную область памяти, т.е. с 5-го байта и т.д.?
Mr.Smart
долгожитель
Сообщения: 1796
Зарегистрирован: 29.03.2008 00:01:11
Откуда: из леса!

Сообщение Mr.Smart »

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:
Аватара пользователя
bloodlines
постоялец
Сообщения: 100
Зарегистрирован: 05.11.2008 10:26:19

Сообщение bloodlines »

А как насчёт такого варианта:
Есть переменные

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

Var
 arr:array[1..18] of byte;
 S:string;


Байты с 5-го по 12 массива arr заняты некоторым значением (например типа Float, Float если я правильно помню занимает 8 байт). Как в переменную S занести значение определённое с 5-го по 12 байт массива arr? Интересуют варианты и для других типов кроме float (string (при условии что знаем длину строки), integer, datetime ), но все нужно заносить в переменную S.
Mr.Smart
долгожитель
Сообщения: 1796
Зарегистрирован: 29.03.2008 00:01:11
Откуда: из леса!

Сообщение Mr.Smart »

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

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

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

Сообщение bloodlines »

а 8 байт это размерность типа double.
Точно, забыл совсем :) .

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

А смысл в строку помещать данные не относящиеся к символам? Или вы хотите что бы данные преобразовывались с начало в строковый вид?

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

Сообщение Mr.Smart »

Простейший вариант преобразовываем в строку и помещаем куда нужно:

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

...
s:=FloatToStr(PDouble(@arr[8])^);
...
Аватара пользователя
bloodlines
постоялец
Сообщения: 100
Зарегистрирован: 05.11.2008 10:26:19

Сообщение bloodlines »

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

Простейший вариант

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

Добавлено спустя 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)^;

В чём ошибка? Подскажите пожалуйста!
Ответить