Работа со строками через адрес (PString, Pointer)

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

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

zub
долгожитель
Сообщения: 2890
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

>>Но не лезу-ли я в "чужую" кучу?...
вполне может залезти, т.к. u непроинициализирован, также вконже нужно незабыть руками почистить хвосты, иначе один рефкаунт строки будет потерян для компилятора.
Должно быть както так:

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

procedure TForm1.Button1Click(Sender: TObject);
var
  u: Pointer;
begin
  u:=nil;//иначе следующая строка может вызвать AV изза возможного мусора в u

  String(u) := Edit2.Text;
  Edit1.Text:= IntToStr(Length(String(u)));

  String(u):=''; //иначе будет мемлик

end;
Аватара пользователя
VirtUX
энтузиаст
Сообщения: 880
Зарегистрирован: 05.02.2008 09:52:19
Откуда: Крым, Алушта

Сообщение VirtUX »

ок. Но почему срабатывает без ошибок этот код?

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

procedure TForm1.Button1Click(Sender: TObject);
var
  u: Pointer;
begin

  u := nil;

  Integer(u) := 5789;
  Edit1.Text:= IntToStr(Integer(u));

end; 

Получается не нужно делать New(Integer(u));
Аватара пользователя
Sharfik
энтузиаст
Сообщения: 840
Зарегистрирован: 20.07.2013 01:04:30

Сообщение Sharfik »

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

procedure TForm1.Button1Click(Sender: TObject);
var
  u: Pointer;
begin

  String(u) := Edit2.Text; /// Тут написано Строка по адресу [b]u [/b]должна получить значение равное edit2.text, однако область памяти [b]u [/b]не назначена.
  Edit1.Text:= IntToStr(Length(String(u))); // если u=nil будет ошибка, если хоть чему то равен, даже случайно, то выдаст длину того куда нацелен.

end;


так понятней, но в зависимости от способа выдачи свойства Text будет по разному работать(напрямую или через функцию). Как и предыдущий вариант.

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

  u := addr(Edit2.Text)


С integer аналогично. В то ли в delphi, то ли еще где то видел галочку, чтобы компилятор переменным функций по умолчанию присваивал значение nil. Т.е. инициализировал. В нашем же случае они негде не инициализированы и рандомны.

Добавлено спустя 16 минут 35 секунд:
VirtUX писал(а):ок. Но почему срабатывает без ошибок этот код?

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

procedure TForm1.Button1Click(Sender: TObject);
var
  u: Pointer;
begin

  u := nil;

  Integer(u) := 5789;
  Edit1.Text:= IntToStr(Integer(u));

end; 

Получается не нужно делать New(Integer(u));

Pointer это числовое значение адреса переменной, т.е. это уже инициализированная ячейка памяти, которая размечена под хранение числа указывающего на другую область памяти. Мы банально меняем значение в переменной, и считываем его из одного и того же места.
Во всех примерах ошибка в том, что надо говорить программе, что работать нужно не с данными в переменной, а с данными по адресу, указанному в переменной.
Аватара пользователя
VirtUX
энтузиаст
Сообщения: 880
Зарегистрирован: 05.02.2008 09:52:19
Откуда: Крым, Алушта

Сообщение VirtUX »

Sharfik писал(а):если u=nil будет ошибка

ничего подобного! При u=nil, Length(String(u)) - выдает размер равным нулю. А Integer(u), при том же u=nil - выдает тоже нуль :)
Я не могу понять - это глюк компилятора, или новая фича FPC 2.6.2?
Аватара пользователя
Sharfik
энтузиаст
Сообщения: 840
Зарегистрирован: 20.07.2013 01:04:30

Сообщение Sharfik »

Я сам поспешил и потом и ниже сказал, что все примеры не правильные.

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

....

var
  Form1: TForm1;
  u: Pointer;
  qwe:string;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  Edit1.Text:= string(u^); // Берем строку по адресу, в первый раз ошибка, во второй раз после нажатия кнопки два ошибки не будет
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  qwe := '333';
  u:=@qwe;
end;


Попробуй так. Сделал в Delphi если что :)
Последний раз редактировалось Sharfik 12.02.2014 18:07:10, всего редактировалось 1 раз.
Аватара пользователя
VirtUX
энтузиаст
Сообщения: 880
Зарегистрирован: 05.02.2008 09:52:19
Откуда: Крым, Алушта

Сообщение VirtUX »

Для наглядности:

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

procedure TForm1.Button1Click(Sender: TObject);
var
  u: Pointer;
  s: string;
begin

  u := nil;
  s := IntToStr(Integer(u));    // Здесь s = '0'
  Edit1.Text:= s;
  Integer(u) := 7878;
  s := IntToStr(Integer(u));    // Здесь s = '7878'
  Edit2.Text:= s;
  u := nil;
  s := IntToStr(Integer(u));    // Здесь снова s = '0'
  Edit3.Text:= s;

end; 


Добавлено спустя 2 минуты 43 секунды:
Sharfik писал(а):Edit1.Text:= string(u^);

Меня интересует Edit1.Text:= string(u);
Sharfik писал(а):qwe := '333';
u:=@qwe;

Это и так понятно, что правильно и по правилам :) Я тут про другое спрашиваю ;)
Аватара пользователя
Sharfik
энтузиаст
Сообщения: 840
Зарегистрирован: 20.07.2013 01:04:30

Сообщение Sharfik »

VirtUX писал(а):Для наглядности:


Ты ему говоришь, что переменную pointer надо рассматривать как integer, т.е. кастануть и работать как с integer. Либо переключись на тип данных record, чтобы ошибки полезли либо пойми, что в примере используешь pointer как integer переменную.
Аватара пользователя
VirtUX
энтузиаст
Сообщения: 880
Зарегистрирован: 05.02.2008 09:52:19
Откуда: Крым, Алушта

Сообщение VirtUX »

Sharfik писал(а):пойми, что в примере используешь pointer как integer переменную

))))))) Спасибо!!! Что-то торможу :)
Аватара пользователя
Sharfik
энтузиаст
Сообщения: 840
Зарегистрирован: 20.07.2013 01:04:30

Сообщение Sharfik »

VirtUX писал(а):Меня интересует Edit1.Text:= string(u);

Мне кажется компилятору пофиг.

ему говорят работай с переменной как строкой, он и работает. Ему мофиг, что размер данных может по габаритам выйти за предел ячейки размечанной для pointer, если string окажется блольше
Edit1.Text:= string(u)
string(u):='4545';
zub
долгожитель
Сообщения: 2890
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

>>ничего подобного! При u=nil, Length(String(u)) - выдает размер равным нулю. А Integer(u), при том же u=nil - выдает тоже нуль
>>Я не могу понять - это глюк компилятора, или новая фича FPC 2.6.2?
Это особенность string`а, пустая строка представляется nil`ем в переменной, так было всегда

>>ок. Но почему срабатывает без ошибок этот код?
потому что в нем нету ниче криминального, другое дело если пытаться писать в область памяти куда указывает неинициализированный (или нулевой) указатель

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

  u := nil;
  Integer(u) := 5789;//ниче криминального, после этого указатель просто будет указывать на ячейку памяти 5789
  PInteger(u)^ := 1234;//так делать нельзя - пытаемся записать 1234 по адресу 5789, но хз что там лежит и разрешена ли туда запись. AV может и не быть сразу, поэтому подобные косяки очень трудно вылавливаются
Аватара пользователя
Дож
энтузиаст
Сообщения: 900
Зарегистрирован: 12.10.2008 16:14:47

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

Чтобы код работал, нужно сделать проверку предположений о том, что при касте String уместится в Pointer, и что пустая строка действительно равна nil:

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

Assert(SizeOf(String) <= SizeOf(Pointer));
Assert(Pointer(String('')) = nil);


Иначе можно нарваться на интересные сюрпризы:

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

[doj@korica ~/temp]$ cat strsize.pas
begin
  Writeln(SizeOf(Pointer), ' ', SizeOf(String));
end.
[doj@korica ~/temp]$ fpc -Mdelphi strsize.pas && ./strsize
4 4
[doj@korica ~/temp]$ fpc strsize.pas && ./strsize
4 256


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

[doj@korica ~/temp]$ cat strnil.pas
begin
  Writeln(Pointer(String('')) = nil);
end.
[doj@korica ~/temp]$ fpc -Mdelphi strnil.pas && ./strnil
TRUE
[doj@korica ~/temp]$ fpc strnil.pas && ./strnil
strnil.pas(2,11) Error: Illegal type conversion: "ShortString" to "Pointer"
strnil.pas(4) Fatal: There were 1 errors compiling module, stopping
Fatal: Compilation aborted
Error: /usr/local/bin/ppc386 returned an error exitcode
zub
долгожитель
Сообщения: 2890
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

Компилятор это делает сам
>>strnil.pas(2,11) Error: Illegal type conversion: "ShortString" to "Pointer"
Конечно это не отменяет возможность кастануть так, что никто не догадается))
Всё вышесказанное мной не относится к ShortString
Аватара пользователя
Дож
энтузиаст
Сообщения: 900
Зарегистрирован: 12.10.2008 16:14:47

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

Компилятор это делает сам
>>strnil.pas(2,11) Error: Illegal type conversion: "ShortString" to "Pointer"


Компилятор не сделал проверку на то, что '' = nil.
zub
долгожитель
Сообщения: 2890
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

>>Компилятор не сделал проверку на то, что '' = nil.
Вы серъезно? Какой в этом смысл?
Тогда уж и

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

Assert(Byte(false)=0);

Каждый раз проверять))
Аватара пользователя
Дож
энтузиаст
Сообщения: 900
Зарегистрирован: 12.10.2008 16:14:47

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

Вы серъезно? Какой в этом смысл?


Да, я абсолютно серьёзен. Покажите в документации (или хотя бы в исходниках fpc), что String(nil) — это всегда пустая строка, а не что-то невалидное.

Каждый раз проверять))


Это, конечно, перебор, ибо это базовая вещь и задокументирована. Но польза от такой проверки тоже может быть

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

[doj@korica ~/temp]$ cat byte.pas
type
  TMySuperBool = (true, false);

begin
  Writeln(Byte(false));
end.
[doj@korica ~/temp]$ fpc byte.pas && ./byte
1
Ответить