![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
#1
|
||||
|
||||
|
Никак не могу врубиться, а почему если оставить FillChar(P^, SizeOf(TData), 0) закомментированным, то выдаёт любимый Access Violation?
Код:
unit TestDataUnit;
interface
uses Forms;
type
TForm1 = class(TForm)
procedure FormShow(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end; // TForm1 = class(TForm)
TData = packed record
FText: String;
end; // TData = packed record
var
Form1: TForm1;
P: Pointer;
implementation
{$R *.dfm}
procedure TForm1.FormShow(Sender: TObject);
begin
P := GetMemory(SizeOf(TData)) ;
// FillChar(P^, SizeOf(TData), 0);
with TData(P^) do
SetString(FText, PChar(nil), 30);
end; // procedure TForm1.FormShow(Sender: TObject)
end. |
|
#2
|
||||
|
||||
|
Код:
type
PData = ^TData;
TData = record
Text: String;
end;
var
p: PData;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
p:=GetMemory(SizeOf(TData));
ZeroMemory(p, SizeOf(TData)); // необязательно вовсе
p^.Text:='hello';
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
p^.Text:='';
FreeMemory(p);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(p^.Text);
end; |
|
#3
|
||||
|
||||
|
Ну во первых у меня Delphi 7, я там ZeroMemory не видел. Во-вторых, я полагаю, FillChar(P^, SizeOf(TData), 0) делает то же, что и ZeroMemory(p, SizeOf(TData)). Но вот для чего оно в данном контексте нужно? Знать бы как работает SetString... Исходника я не нашёл у себя. Мож в инете?
|
|
#4
|
||||
|
||||
|
у меня тоже Delphi 7, о чем написано в профиле.
Код:
var
s: String;
begin
SetString(s, PChar('hello'), 5);
ShowMessage(s);
end; |
|
#5
|
||||
|
||||
|
Да, извиняюсь, про Delphi 7 просмотрел. А для чего тут-то SetString? Можно просто s := 'hello'. Но вопрос был не об этом. Вопрос: почему без FillChar выдаёт Access Violation? И, кстати, если написать так
Код:
procedure TForm1.FormShow(Sender: TObject);
var
s: String;
begin
s := 'hello';
ShowMessage(s);
P := GetMemory(SizeOf(TData)) ;
// FillChar(P^, SizeOf(TData), 0);
with TData(P^) do
SetString(FText, PChar(nil), 30);
end; // procedure TForm1.FormShow(Sender: TObject) |
|
#6
|
||||
|
||||
|
ZeroMemory, если мне не изменяет мой склероз вызывает FillChar
|
|
#7
|
|||
|
|||
|
Потому что строка в Дельфи - это объект с автоматическим временем жизни и подсчётом ссылок. В константно1 строке счётчик равен -1, во вновь созданной - 0;
Любое присваивание в строку - это: 1)Проверить, на Nil старый указатель. 2)Если там Nil, то перейти на 6) 3)Проверить счетчик ссылок, если там не 1, то перейти на 5) 4)Освободить память, занимаемую строкой, перейти на 6) 5)Если счётчик не -1, то уменьшить счётчик 6)Собственно присвоить новый указатель 7)Проверить на Nil новый указатель 8)Если там Nil, то Exit 9)Проверить счётчик. Если там не -1, то увеличить счётчик. В многопоточном режиме добавляются Interlocked операции Строковые локальные переменные процедур и поля классовых переменных после конструкторов инициализируются Nil`ами. GetMemory осуществляет только заказ памяти и ничем его не прописывает. Поэтому на шаге 1) у Вас будет не Nil, а на шаге 4) - Access Violation. |
| Этот пользователь сказал Спасибо icWasya за это полезное сообщение: | ||
BBBCat (14.03.2013)
| ||
|
#8
|
||||
|
||||
|
Сорри, электричество вырубали у нас
Ну наконец-то внятный ответ! А то все вопрос читают по диагонали Про строку - я это в курсе, а вот про SetString... Ну примерно так я и предполагаю, правда с одним 'но'. Хэлп из Delphi: For a long string variable, SetString sets S to reference a newly allocated string of the given length. И далее: If there is not enough memory available to create the string, an EOutOfMemory exception is raised. Following a call to SetString, S is guaranteed to reference a unique string, that is a string with a reference count of one. Т.е:1)На Nil старый указатель не проверяется. 3)Счетчик ссылок не смотрится, а сразу устанавливается на единицу 7)Проверить на Nil новый указатель и 8)Если там Nil, то Exit - вот здесь-то и должно родиться EOutOfMemory Про Access Violation ни слова. Т.е. исходя из хэлпа должно работать без FillChar(P^, SizeOf(TData), 0), а исходя из практики - так как вы отписали. Такая ситуация немного напрягает. А вдруг там ко всему вышесказанному ещё что-то есть. Поэтому хотелось бы точно знать, как SetString работает. В смысле на исходник глянуть. А у вас откуда все эти сведения? Вот ещё что забыл: из сообщения icWasya рождается объясниние, почему во втором из приведённых мной здесь коде всё нормально срабатывает при добавлении Код:
s := 'hello'; ShowMessage(s); Последний раз редактировалось BBBCat, 14.03.2013 в 12:43. |
|
#9
|
|||
|
|||
|
Как я сказал, эта процедура вызывается при ВСЕХ присваиваниях строк.
Как раз старый указатель на Nil проверяется всегда. А поскольку у Вас там мусор - то и ошибка. А в хелпе написано, что делается с НОВОЙ строкой. То есть создаётся новая строка, а если не получилось(Nil), то и вызывается EOutOfMemory. По поводу того, что при выполнении шамашских действий начинает работать. Мусорный указатель не всегда приводит к Access Violation. Или приводит, но не сразу. Или ошибка выскочит где-нибудь через час работы программы на ровном месте. В Вашем случае этот указатель мог совпасть с указателем на вот эту строку 'hello'. Поскольку она константная, счётчик у неё равен -1, а для таких строк FreeMem не вызывается. И запомните - если программа работает правильно(или Вам так кажется), это не значит, что в ней нет ошибок. |
|
#10
|
||||
|
||||
|
Согласен, программа без глюков - это значит глюк у программиста
И да, ну очень сильно похоже на реакцию на мусор. Но вот в хэлпе-то не разграничено для новой строки или для существующей. Просто для длинной и всё. Непонятка! По поводу строчки с 'hello' - приблизительно как вы и сказали, это вопросов не вызывает. Но вот как она у меня умудрялась со 100%-ной стабильностью выдавать ошибку на третьем проходе, а потом на каждом пятом? Стабильно не смотря на те действия, которые я при этом проводил с компом. Всё же хочу повторить вопрос - откуда у вас такие, как бы выразится, алгоритмические сведения о работе SetString? |
|
#11
|
||||
|
||||
|
Я с вас сильно удивляюсь господа.
Исходник SetString не судьба посмотреть? Там 3 строчки всего, и сразу все понятно становится. |
|
#12
|
||||
|
||||
|
Цитата:
Извиняюсь, не с этого начал, но во втором сообщении точно написал ![]() Да и ZeroMemory я чёй-та не найду. Где он? Последний раз редактировалось BBBCat, 14.03.2013 в 14:25. |
|
#13
|
||||
|
||||
|
Код:
procedure _SetString(s: PShortString; buffer: PAnsiChar; len: Byte);
begin
Byte(s^[0]) := len;
if buffer <> nil then
Move(buffer^, s^[1], len);
end;
|
|
#14
|
||||
|
||||
|
Не, ну это-то я уже видел. Это ж для ShortString. Там и вопроса-то такого не возникло бы. А вот что для String?
|
|
#15
|
||||
|
||||
|
Цитата:
Код:
procedure ZeroMemory(Destination: Pointer; Length: DWORD); begin FillChar(Destination^, Length, 0); end; |
| Этот пользователь сказал Спасибо NumLock за это полезное сообщение: | ||
BBBCat (14.03.2013)
| ||