Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.10.30;
Скачать: CL | DM;

Вниз

Access Violation при использовании StrUpper   Найти похожие ветки 

 
Anatoly Podgoretsky ©   (2005-10-09 17:47) [40]

raiks   (09.10.05 17:28) [37]
Вот это и доказывает, что представляет. Ознакомься с принципами работы Виндоус по работе с памятью, в части аттрибутов доступа.


 
sniknik ©   (2005-10-09 17:48) [41]

raiks   (09.10.05 17:34) [38]
PChar это не стринг.

> Разница лишь в том, что в С++ строке присвоено значение при объявлении
ну если нет разници то делай аналогично.

char * c;

c = "suxx";
DoSomething(c);

это тоже самое, в с/с++?. (боюсь ошибиться, т.к. с не знаю, но по моему нет)


 
sniknik ©   (2005-10-09 17:53) [42]

raiks   (09.10.05 17:34) [38]
адекватная запись в дельфи будет (более менее ;)

const с: array[0..length("suxx")] of char = "suxx";
begin
 DoSomething(c);
end;


 
raiks   (2005-10-09 17:56) [43]

Все! Всем спасибо. Методом научного тыка разобрался :) Надо было писать так:

var
 p: PChar;
begin
 p:="suxx";
 p:=StrNew(p);
 StrUpper(p);       // No Access Violation :)
end;

Странно, что борландовцы этого в хэлпе не написали.
Уфф...


 
sniknik ©   (2005-10-09 18:04) [44]

> Методом научного тыка разобрался :)
нифига ж себе "научный тык"
это после прямых указаний (только за свое. есть и реньше)

sniknik ©   (09.10.05 17:25) [36]
...
> в первом память не выделена.

> Странно, что борландовцы этого в хэлпе не написали.
не там смотрел. это основы работы с динамическими переменными (PChar в частности)


 
GuAV ©   (2005-10-09 18:53) [45]

raiks   (09.10.05 17:56) [43]

Нужно освобождать через StrDispose.


 
Anatoly Podgoretsky ©   (2005-10-09 19:06) [46]

raiks   (09.10.05 17:56) [43]
Смотрим в справку backward compatibility routines
И смотрим справку по StrDispose StrDispose is provided for backward compatibility only


 
Джо ©   (2005-10-09 20:19) [47]


> [29] begin...end ©   (09.10.05 16:46)
>Description: StrUpper converts Str to uppercase and returns Str.
> [30] Anatoly Podgoretsky ©   (09.10.05 16:54)

Да, это я "зеванул".
Но в чем загадочная цель возвращать тот же самый указатель, который и был передан. Я, собственно, к тому и вел, что именно такая декларация функции не делает очевидным (без докумментации) ее назначение. Т.е, просто нарушается принцип сокрытия подробностей реализации.


 
Anatoly Podgoretsky ©   (2005-10-09 20:26) [48]

Джо ©   (09.10.05 20:19) [47]
Для того что бы можно было использовать как функцию, а значит включить как параметр. Почти все Str функции так построены. То есть только для удобства. На самом деле это как бы "var" параметр


 
y-soft ©   (2005-10-09 20:28) [49]

>Джо ©   (09.10.05 20:19) [47]

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

Ничего загадочного. Чтобы потом не забывали освобождать выделенную под результат память как раз по причине принципа сокрытия реализации :)

Хотя в такого рода процедурах для большей ясности принято возвращать результат через var параметр

Что-то типа

procedure StrUpper(var S: PChar);


 
y-soft ©   (2005-10-09 20:29) [50]

>Anatoly Podgoretsky ©   (09.10.05 20:26) [48]

Опередил :)


 
begin...end ©   (2005-10-09 20:34) [51]

> Джо ©   (09.10.05 20:19) [47]

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

Представьте, что StrUpper -- это процедура, и ей указатель передаётся как var-параметр. Теперь попробуйте переписать хотя бы тот неправильный пример из справки. Сравните читабельность кода в этих двух вариантах.

P.S. А Вы на C никогда не писали? strcpy, strcat, memcpy, itoa... Вроде, пользуются люди, и ничего...


 
Anatoly Podgoretsky ©   (2005-10-09 20:45) [52]

begin...end ©   (09.10.05 20:34) [51]
Это не var параметр, передается по значению, здесь var параметр и не требуется, поскольку значение не меняется.

function StrUpper(Str: PChar): PChar;


 
begin...end ©   (2005-10-09 21:02) [53]

> Anatoly Podgoretsky ©   (09.10.05 20:45) [52]

Я понимаю, что не меняется. Я написал так из-за [24].

Но даже если и без var-параметра -- всё равно читаемость ухудшится.


 
raiks   (2005-10-09 22:29) [54]

Anatoly Podgoretsky:

Несмотря на то, что функция StrUpper возвращает указатель, сам аргумент тоже изменяется - PChar всегда передается по ссылке вне зависимости от того, объявлен он как var или нет (это касается всех указателей, а PChar - всего лишь указатель на строку с нулевым окончанием).


 
Anatoly Podgoretsky ©   (2005-10-09 22:40) [55]

Ничего здесь по ссылке не передается, а передается значения указателя, вот если ты объявишь var P: PChar вот тогда будет по ссылке.
А что за тип PChar объяснять не стоит. Это все таки не указатель на строку с нулевым символом, это не более чем соглашение, которое не всегда и использвется, иногда передается на "строку" и без завершающего нуля, дополнительно передается и длина и эти функции как правило не должны анилизировать этот ноль, а работать с переданной длиной.
Я уже говорил, ты не совсем разобрался что такое PChar отсюда и твои проблемы.


 
begin...end ©   (2005-10-10 13:35) [56]

> raiks   (09.10.05 22:29) [54]

Гм... Давайте всё-таки вместе разберёмся и поставим все точки над "i", чтобы никаких вопросов не осталось.

Выясним, почему дельфишный код из [31] не работает, а дельфишный же код [37] работает. Поскольку Вы пишете подпрограммы на ассемблере, думаю, что разобраться труда не составит.

1. Код, аналогичный [31]:

procedure P;
var
 P: PChar;
begin
 P := "suxx"; // (1)
 P^ := "a"    // (2)
end


Этот код от [31] принципиально не отличается -- вначале переменной типа PChar присваивается константная строка, затем производится попытка изменить эту строку (в данном случае -- поменять первый символ).

Ставим контрольную точку на выделенной строке, вызываем процедуру, жмём Ctrl-Alt-C и смотрим в окно ЦП. Вот весь ассемблерный код этой процедуры (строки ассемблерного кода пронумерованы соответственно строкам дельфишного):

(1) mov eax,$0044d950
(2) mov byte ptr [eax],$61
(3) ret


Первое, что можно заметить -- оптимизатор не стал размещать локальную переменную P в стеке, а использует для этого регистр eax. Т.е. содержимое eax -- это содержимое переменной P. Начинаем пошагово выполнять код (по F8).

В строке (1) этой переменной присваивается значение $0044d950. У Вас этот адрес может быть другим. Что это за значение? В окне CPU переходим в окошко с содержимым памяти, в контекстном меню выбираем "Goto Address..." и вводим либо "$0044d950" (разумеется, если у Вас адрес отличается от этого, нужно ввести именно Ваш), либо (если строка (1) уже выполнилась) просто "eax". Видим, что в памяти по этому адресу как раз и находится строка "suxx", причём завершающаяся нулём. Вот в этом-то всё присваивание константной строки PChar-переменной и заключается, понимаете? Память для строки уже выделена (она была выделена ещё при запуске Вашей программы), строка уже находится в памяти, а всё присваивание сводится к тому, что в переменную P просто помещается адрес этой строки. Больше ничего не происходит.

Идём дальше. В строке (2) пытаемся поменять первый символ строки, т.е. в байт по адресу, содержащемуся в eax, пытаемся записать символ "a" (с кодом $61). Нетрудно убедиться, что именно здесь и происходит AV. Почему? Тут уже не обойтись без стороннего отладчика, т.к., насколько я знаю, встроенный отладчик не позволяет посмотреть на атрибуты доступа памяти. Подойдёт любой другой, позволяющий это увидеть (например, я пользуюсь OllyDbg -- его можно свободно скачать в Сети). Всё, что нужно -- это найти ту самую строку "suxx" (а если в коде ничего не изменялось, то она так и будет расположена по адресу $0044d950) и посмотреть, в какой области памяти она находится. Можно увидеть, что у диапазона адресов $004D0000..$00556000 (а именно в этот диапазон входит адрес строки) атрибуты -- RE, что означает read + execute. А W (write) -- нету. Т.е. в этот диапазон адресов писать нельзя. Отсюда и AV. И то, что константная строка размещена в памяти без права записи -- по-моему, вполне логично.

(3) -- выход из подпрограммы.

2. Код, аналогичный [37]:

procedure P;
var
 N: array [0..4] of Char;
begin
 N := "suxx";
 N[0] := "a"
end

(1) add esp,-$08
(2) mov eax,[$0044d964]
(3) mov [esp],eax
(4) mov al,[$0044d968]
(5) mov [esp+$04],al
(6) mov byte ptr [esp],$61
(7) pop ecx
(8) pop edx
(9) ret


Тут уже посложнее.

(1) -- выделение памяти под локальную переменную N (массив). Достаточно 5 байт, но компилятор выделяет 8 -- видимо, ему так удобнее.

(2) -- в eax помещается содержимое памяти по адресу $0044d964. У Вас этот адрес опять может быть другим. Это опять адрес константной строки "suxx" (можно проверить). Т.е. в eax копируются (читать-то ведь по адресу $0044d964 можно!) первые 4 символа строки (а она состоит из пяти -- не забываем про завершающий ноль).

(3) -- эти 4 символа строки копируются в начало массива N (esp -- это и есть адрес массива).

(4), (5) -- то же, что и (2) и (3), только для последнего символа.

(6) -- запись в первый символ массива. Заметьте -- не в ту память, где изначально находилась константная строка, а в копию этой строки. В том, что в память по адресу, содержащемуся в ESP, писать можно, опять легко убедиться с помощью отладчика (не встроенного). У меня атрибуты такие: RW (read + write), и ещё guarded (типично для стека). Поэтому никакого AV тут и нету.

(7), (8), (9) -- балансировка стека и выход из процедуры.

-------------------------------------------------------------------------------

Теперь скажите -- всё понятно?


 
Игорь Шевченко ©   (2005-10-10 14:16) [57]

"You can"t modify a constant, float upstream, win an argument with the IRS, or satisfy this compiler"
(c) MPW C Compiler


 
GrayFace ©   (2005-10-11 16:46) [58]

Anatoly Podgoretsky ©   (09.10.05 16:18) [22]
AV будет, нет прав на запись в данную область.
Другая типичная ошибка, S string
OemToChar(PChar(S), PChar(S));

А почему так нельзя?


 
Джо ©   (2005-10-11 16:50) [59]


>  [57] Игорь Шевченко ©   (10.10.05 14:16)
> "You can"t modify a constant, float upstream, win an argument
> with the IRS, or satisfy this compiler"
> (c) MPW C Compiler

Класс :)


 
Anatoly Podgoretsky ©   (2005-10-11 17:32) [60]

GrayFace ©   (11.10.05 16:46) [58]
Особенности работы функции PChar, если аргумент пустой, то будет возвращена строка-константа из кодового сегмента, которая естественно ReadOnly



Страницы: 1 2 вся ветка

Текущий архив: 2005.10.30;
Скачать: CL | DM;

Наверх




Память: 0.58 MB
Время: 0.041 c
1-1128396828
SHVictor
2005-10-04 07:33
2005.10.30
Редактирование поля в StringGrid


14-1129023072
Андрей Жук
2005-10-11 13:31
2005.10.30
На www.dynamo.kiev.ua раздают бесплатные почтовые ящики (2 Гб)


14-1128730403
NoName__1
2005-10-08 04:13
2005.10.30
HDD


8-1117665158
TechnoDreamer
2005-06-02 02:32
2005.10.30
Autolevels, autocolor и autocontrast


14-1128950244
Alexander666
2005-10-10 17:17
2005.10.30
Ремонт ноутбука





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский