Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2008.02.24;
Скачать: [xml.tar.bz2];

Вниз

Статьи по работе с указателями   Найти похожие ветки 

 
Putnik ©   (2008-01-19 16:19) [0]

Уважаемые мастера, подскажите пожалуйста, что надо почитать человеку "у которого отсутствует часть мозга ответственная за указатели", извиняюсь если не правильно привел цитату. Просто я действительно это не понимаю, а все-таки хотелось бы. Или такое знание не придет пока в этом действительно не возникнет необходимости?


 
Palladin ©   (2008-01-19 16:40) [1]

Любые данные находяещиеся в памяти имеют свой адрес в ней
Память для приложения это один огромадный массив
теоретически такой Array [0..4*1024*1024*1024-1] of Byte
практически такой Array [0..2*1024*1024*1024-1] of Byte
бывает и такой Array [0..3*1024*1024*1024-1] of Byte

Так вот, переменная типа указатель, он же pointer, содержит, всего лишь, индекс в этом массиве с которого начинаются данные на которые он указывает


 
korneley ©   (2008-01-19 16:46) [2]

Лишнер Рэй Секреты Delphi 2: Пер. с англ./Рэй Лишнер. - К.: НИПФ - "ДиаСофт Лтд.", 1996. - 800 с. ISBN 966-7033-10-4 13
Там много чего полезного, в том числе и по "кучам"


 
DVM ©   (2008-01-19 16:49) [3]


> Palladin ©

Про nil забыл сказать.


 
Putnik ©   (2008-01-19 17:33) [4]

А Ч. Калверт? Его можно читать? Если честно, то так просто, что ничего непонятно(, но слышал положительные отзывы...
> korneley © Спасибо, почитаю, хотя боюсь, мое "это" и правда неизлечимо(


 
Черный Шаман   (2008-01-19 20:23) [5]


> Putnik ©   (19.01.08 16:19)
>
> Уважаемые мастера, подскажите пожалуйста, что надо почитать
> человеку "у которого отсутствует часть мозга ответственная
> за указатели", извиняюсь если не правильно привел цитату.
>  Просто я действительно это не понимаю, а все-таки хотелось
> бы. Или такое знание не придет пока в этом действительно
> не возникнет необходимости?


В программе нет переменных, есть неявные ссылки на адреса памяти представляемые в программе в виде имён переменных и операций с ними. Так что производя вычисления с переменными ты всего лишь берёшь данные из определённых адресов памяти, загружаешь в регистры процессора, вычисляешь и заносишь в другие адреса памяти.

Так вот, указатель это всего лишь переменная которой можно явно задать адрес в линейной памяти на которую она будет указывать, в том числе и на адрес в котором лежит значение переменной.

Функция разыменования указателя позволяет с данными лежащими по присвоенному адресу общаться как с обычными данными переменных.

Любому асемблерщику работа с указателями проста и понятна. Хотя сам asm кроме как для embeded и геймдева уже и никому не нужен.


 
DVM ©   (2008-01-19 20:25) [6]


> Хотя сам asm кроме как для embeded и геймдева уже и никому
> не нужен.

А оптимизация под MMX/SSE/2/3 ?


 
@!!ex ©   (2008-01-19 20:48) [7]

> А оптимизация под MMX/SSE/2/3 ? ... делается на уровне компилятора...


 
DVM ©   (2008-01-19 20:52) [8]


> ... делается на уровне компилятора...

Сказки это все.


 
@!!ex ©   (2008-01-19 20:53) [9]

> [8] DVM ©   (19.01.08 20:52)

LOL


 
DVM ©   (2008-01-19 21:02) [10]


> LOL

Ты серьезно считаешь, что компилятор сделает всю работу по оптимизации под SSE за тебя? Что ж интел все свои библиотеки ручками оптимизирует, а не полагается на свой (в принципе отличный в плане оптимизации под процы Интел) компилятор?


 
Kenny   (2008-01-19 21:48) [11]

> @!!ex ©   (19.01.08 20:48) [7]
>> А оптимизация под MMX/SSE/2/3 ? ... делается на уровне компилятора...


И правда сказка. Покажите мне этот компилятор! )


 
korneley ©   (2008-01-19 21:56) [12]


> Черный Шаман   (19.01.08 20:23) [5]
>...Любому асемблерщику
> работа с указателями проста и понятна. Хотя сам asm кроме
> как для embeded и геймдева уже и никому не нужен

C первым согласен, а поэтому второе - не совсем корректно. Для того и надо изучение asm, чтоб приблизиться к пониманию "как, весь этот джаз, работает?"


 
@!!ex ©   (2008-01-19 22:53) [13]

> И правда сказка. Покажите мне этот компилятор! )

Intel C++ Compiler


 
@!!ex ©   (2008-01-19 22:55) [14]

> Что ж интел все свои библиотеки ручками оптимизирует, а
> не полагается на свой (в принципе отличный в плане оптимизации
> под процы Интел) компилятор?

Потому что ассемблер всегда был быстрее кода сгенерированного компилятором, да вот только SSE тут непричем.


 
Черный Шаман   (2008-01-19 23:11) [15]


> @!!ex ©   (19.01.08 22:55) [14]
>
> > Что ж интел все свои библиотеки ручками оптимизирует,
> а
> > не полагается на свой (в принципе отличный в плане оптимизации
> > под процы Интел) компилятор?
>
> Потому что ассемблер всегда был быстрее кода сгенерированного
> компилятором, да вот только SSE тут непричем.


Только пытаясь на asm решить хоть одну более менее серьезную задачу(не мелкие библиотечки или embeded, где он иногда нужен) видим такую цену решения, что у начальства глаза на лоб лезут.

Не всегда быстрое выполнение и требуемый малый объем памяти хорошо. Это работает когда не нужно один и тот же проект переделывать и подшаманивать раз 10. Тогда важнее уже не скорость, а возможность быстрого изменения системы под требования.

Тот же 1С тормозит, но большинству подходит, так как позволяет свести нормально тараканы руководства, черную бухгалтерию и бухгалтерию для налоговой, что от него и требуется. А на сервер руководство и 10000$ может выделить при потребности.


 
DrPass ©   (2008-01-19 23:53) [16]


> @!!ex ©   (19.01.08 22:53) [13]
> > И правда сказка. Покажите мне этот компилятор! )
>
> Intel C++ Compiler

Ну и каким образом этот компилятор сможет догадаться, что, допустим, "данную матрицу надо упаковать в четырехбайтовые переменные и преобразовать с помощью ММХ"? 8-)


 
KilkennyCat ©   (2008-01-20 00:00) [17]

ну вот. уже и ассемблер в топку закинули. эдак детям еще при рождении в задницу начнут запихивать калькулятор, чтоб таблицу умножения похоронить.


 
KilkennyCat ©   (2008-01-20 00:01) [18]

про ембедед мне тож понравилось. типа, фигня. одна миллиардная от всего прочего...


 
DVM ©   (2008-01-20 00:30) [19]


> @!!ex ©   (19.01.08 22:53) [13]


> Intel C++ Compiler

Ты его сам то использовал? Или наслушался сказок?


 
DVM ©   (2008-01-20 00:36) [20]


> @!!ex ©   (19.01.08 22:55) [14]


> Потому что ассемблер всегда был быстрее кода сгенерированного
> компилятором, да вот только SSE тут непричем.

Не всегда. Зависит от умения того, кто писал на этом самом ассемблере. У меня полно примеров есть из реальной практики. когда код на чистом паскале, оказывался в 2 раза быстрее кода на ассемблере, написанного каким то новичком в этом деле, слепо верящим в то, что он напишет круче, чем сгенерирует компилятор, который писали отнюдь не новички.

А SSE тут причем. Чтобы его применить и к месту тут как правило недостаточно простых замен одного на другое, как, грубо говоря поступает компилятор. Тут с фантазией надо подойти. Это под силу только человеку. А компилятор тут может действовать лишь по каким то шаблонам.


 
MsGuns ©   (2008-01-20 02:58) [21]

"Въехать" в указатели без понимания механизма адресации ВМ невозможно.


 
ketmar ©   (2008-01-20 16:57) [22]

>[21] MsGuns©(20.01.08 02:58)
>"Въехать" в указатели без понимания механизма адресации ВМ невозможно.

то-то я на Z80 их только по выходу в астрал понимал…


 
DrPass ©   (2008-01-20 16:59) [23]


> ketmar ©   (20.01.08 16:57) [22]


> то-то я на Z80 их только по выходу в астрал понимал…

С его линейным адресным пространством? Как же тебя наверное колбасило, когда с х86 познакомился? ;-)


 
ketmar ©   (2008-01-20 17:32) [24]

>[23] DrPass©(20.01.08 16:59)
>Как же тебя наверное колбасило, когда с х86 познакомился? ;-)
давай не будем о печальном. я тогда как раз решил отучаться ругаться матом. отучился. успешно. стал на нём просто разговаривать.


 
Дмитрий Белькевич ©   (2008-01-20 21:06) [25]

>Просто я действительно это не понимаю, а все-таки хотелось бы

Примем платформу - Intel + Windows. Считаем, что указатель 32 бита, память - линейна и непрерывна, её 4 гигабайта. Как менждер памяти винды и делфи это разруливают, что бы оно почти так было в реальном приложении - это их проблемы. За это им уплочено.

Тогда всё просто. Есть т.н. ячейки памяти. Их, соответственно, 4 с немногим миллиарда. Они пронумерованы с нулевой по 4-х миллиардную. Все ячейки - 8-ми битные (1 байт).

Допустим, есть некоторая переменная p типа pointer. Она - 32-х битная, то есть занимает 4 байта. И лежит где-то в этой же памяти.
Допустим, есть тоже 32-х битная переменная i, первый байт из четырёх которой лежит в ячейке (по адресу) номер 54564786.

Так вот, если в переменную p записать число 54564786, это и будет указатель на переменную i. Затем, "получив" число 54564786 из ячейки p можно добраться до переменной i, "взяв" данные по адресу 54564786 - операция называется "разыменовывание указателя".

По nil"у еще скажу. Изначально в инициализированных переменных содержаться нули. Если в переменную p до того, как из неё будут читать, ничего не писали, то говорят, что указатель не инициализирован. Т.е. указывает "в никуда", хотя на самом деле указвает на 0-ю ячейку). Если попробовать разыменовать указатель, который указывает на ячейку номер 0, это приведет к исключению.

Как это работает.

Была создана специальная область памяти-ловушка (1 кб вроде - точно не помню), находяшаяся в самом начале адрессного пространства. Т.е. от ячейки номер 0 и выше. Создана, что бы ловить ошибки при работе с неинициализированными или неверно инициализированными указателями. При попытке доступа в эту область происходит исключение.

По указателям еще.

Бывают двух видов - типизированные и нетипизированные. Нетипизированный - это обычный Pointer. Типизированные - все остальные. Например, PChar - указатель на Char. Разницы между ними принципильной нет. Это те же 4 байта, в которые записан адрес переменной. Только, например, в случае PChar, это может быть не любая переменная, а только переменная типа Char.

Реализуется это на уровне компилятора. После того, как компилятор собрал проект в экзешник, информация о том, что  p - это был указатель на Byte, или на Char, или на Integer, нигде не сохраняется.

Естественно, в памяти переменную типа Char от переменной типа Byte отличить невозможно. Соответственно, указатели PByte и PChar (как и любые другие) в памяти - это совершенно одинаковые и ничем не выдающиеся переменные.

Вроде нигде не наврал, если что - мастера поправят...


 
Kerk ©   (2008-01-20 21:08) [26]


> 1 кб вроде - точно не помню

64кб


 
Дмитрий Белькевич ©   (2008-01-20 21:11) [27]

>Затем, "получив" число 54564786 из ячейки p

читать: Затем, "получив" число 54564786 из переменной p

p.s. редактирования форуму ну очень не хватает...


 
DVM ©   (2008-01-20 21:13) [28]


> Дмитрий Белькевич ©

Еще стоит добавить про @ и ^. Также про GetMem/FreeMem и New/Dispose, наверное.


 
DVM ©   (2008-01-20 21:16) [29]

И про операции с указателями. И про то, как ведут себя некоторые функции типа Inc(p)


 
homm ©   (2008-01-20 21:19) [30]

> [25] Дмитрий Белькевич ©   (20.01.08 21:06)
> Была создана специальная область памяти-ловушка (1 кб вроде
> - точно не помню),

64К снизу и стока же сверху от адресного пространства в 2 гига, если она не изменяет.


 
Дмитрий Белькевич ©   (2008-01-21 04:18) [31]

Добавим...

Операция @.

Позволяет получить номер ячейки (адрес) переменной. В верхнем примере @i будет равно 54564786.

Операция p := @i занесёт данные об адресе переменной i в указатель p.

Операция ^.

Когда значек ^ стоит после названия переменной-указателя (p^), он обозначает, что указатель разименовывают. Как я писал выше, обращаются не к данным в переменной p, а к данным, на которые указывает переменная p.
То есть p^ и i - одно и то же. Для нас. Но не для компилятора. Что бы компилятор понял, что можно делать с p^, что бы он знал, на что собственно указывает указатель (понятно, что он всегда указывает на какую-то ячейку памяти, но там может находиться начало любой переменной или объекта), он должен быть типизированным. То есть он должен быть не pointer, а, например, PInteger. Тогда p^ будет распознано компилятором именно как переменная типа integer.

Если мы предварительно инициализировали указатель p адресом перменной i, написав p := @i, то после этого мы можем к i обращаться как i и как p^.

С ним (с p^) можно делать любые операции, которые возможны с integer"ом. При этом сам указатель p не меняется, меняются данные в переменной, на которую он указывает, то есть в переменной i.

Кроме этого значек ^ может использоваться в описании типа указателей в секции "type", вот несколько строк из модуля system.pas:

type
PAnsiString = ^AnsiString;
end;

Здесь описывается тип PAnsiString. Тип PAnsiString описывается, как указатель на AnsiString. Именно этой строкой компилятору дают понять, что все типизированные указатели типа PAnsiString могут указывать только на переменные типа AnsiString. Это позволяет компилятору проверят верность передачи параметров в процедуры и верность работы с разыменованными указателями.

Операции сложения/вычитания с указателями.

Так как, собственно, указатели - это самые обычные 32-х разрядные числа, ничто не мешает их складывать и вычитать. В компиляторе Делфи, однако, есть ограничение - такие операции возможны только с указателями типа PChar.

Например, с указателем p: pchar можно написать p := p + 10;
Что при этом произойдет. Допустим, указатели изначально указывал на ячейку 54564786. После команды p := p + 10; он будет указывать на ячейку 54564796. Вполне вероятно, что в этой ячейке может содержаться 11-й символ массива символов s. Так же вероятно (в случае, если размер s меньше 11-ти), что в этой ячейке будет либо мусор, либо уже другая переменная, либо эту ячейку вообще нельзя читать и/или писать. Тогда, в лучшем случае можно получить т.н. AV - acess violation, в худшем - этот же AV рано или поздно появится у заказчика, который работает на другом конце Земли. Поэтому в случае применения операций сложения/вычитания с указателями желательно каким-то образом следить за границами массивов.

Inc(p) инкрементирует указатель. То есть добавляет к нему единицу, "продвигая" его на одну ячейку вверх. Работает только с PChar.

Приведение указателей и работу с памятью писать пока не буду - может вообще всё, что писал не понятно - нет смысла дальше продвигаться.

Вообще, в объяснениях часто неясна какая-то мелочь. Относитльно недавно объяснял человеку работу с памятью. После получаса нашлось непонимание - думал, что ячейки памяти 32-х битные (в принципе, логично - камни-то 32-х разрядные, кто знает, как там оно в нутре, мне проще - я схемотехнику знаю).


 
Дмитрий Белькевич ©   (2008-01-21 04:31) [32]

>но там может находиться начало любой переменной или объекта

Добавлю: а может не находится вообще ничего интересно, либо мусор, либо может быть "середина" переменной, либо вообще кусок кода, а не данные. То есть, что в поинтер положили, на то он и указывает. А уж что конкретно там лежит, на что он указывает - известно только Богу. Если вы - хороший программист, то еще и вам.

>камни-то 32-х разрядные

Добавлю: на самом деле, в/из процессор/а данные чаще всего подчитываются именно по 32 (а в 64х - по 64) бита, но это - уже другая история...


 
Юрий Зотов ©   (2008-01-21 04:48) [33]

Inc(p) работает не только с PChar, а с любым типизированным указателем. Увеличивает его как раз на размер того самого типа.

Из хелпа на Inc:

Note: If X is a pointer type, it increments X by N times the size of the type pointed to. Thus, given

type
 PMytype = ^TMyType;

and

var
 P: PMyType;

the statement

Inc(P);

increments P by SizeOf(TMyType).


 
Юрий Зотов ©   (2008-01-21 04:52) [34]

> думал, что ячейки памяти 32-х битные (в принципе, логично - камни-то
> 32-х разрядные, кто знает, как там оно в нутре,

А пофиг, как оно там внутре. Байт, по определению - это минимально адресуемая область памяти. Поэтому, как бы оно там внутре ни было, а адресация все равно всегда побайтовая.


 
Сергей Суровцев ©   (2008-01-21 09:40) [35]

>Дмитрий Белькевич ©   (20.01.08 21:06) [25]

Редкий для форма по полноте охвата ответ. Осталось только резюмировать, а нафига собственно это все нужно? Область оправданного применения.


 
DVM ©   (2008-01-21 10:43) [36]


> Сергей Суровцев ©   (21.01.08 09:40) [35]


> а нафига собственно это все нужно?

Зачем нужны указатели? Или зачем нужно подробное объяснение, что такое указатели?


 
Skier ©   (2008-01-21 12:10) [37]

>Сергей Суровцев ©   (21.01.08 09:40) [35]

> а нафига собственно это все нужно?

Вот и Билл Гейтc так же подумал и "изобрел" .NET Блин!
Вы ему не помогали?


 
Дмитрий Белькевич ©   (2008-01-21 12:36) [38]

>Inc(p) работает не только с PChar, а с любым типизированным указателем. Увеличивает его как раз на размер того самого типа.

Спасибо за дополнение. Действительно так.

>А пофиг, как оно там внутре. Байт, по определению - это минимально адресуемая область памяти.

Человек думал, что указатель указывает именно на 32 бита. И, если прибавить единицу к указателю, то адрес переместиться на 4 байта вверх.
Опять же, без понятия "как внутре" тяжело объяснять преимущества выравнивания по границе слова.


 
Сергей Суровцев ©   (2008-01-21 12:37) [39]

>DVM ©   (21.01.08 10:43) [36]
>Зачем нужны указатели? Или зачем нужно подробное объяснение, что такое указатели?

Объяснения нужны и хороши. В них только не указана область целевого применения.

>Skier ©   (21.01.08 12:10) [37]
>Вот и Билл Гейтc так же подумал и "изобрел" .NET Блин!
Вы ему не помогали?

Скорее ему помогала незабвенная корпорация Nuntaked. Ее благословенный Clipper до сих пор встречается в ходу, особенно в гос.структурах.


 
Юрий Зотов ©   (2008-01-21 12:46) [40]

> Сергей Суровцев ©   (21.01.08 12:37) [39]

Есть большой массив структур. Размер одной структуры - 10 кБ. По ходу работы программы длина массива часто меняется и, кроме того, требуется его частая пересортировка. Скорость работы программы имеет значение.



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

Форум: "Прочее";
Текущий архив: 2008.02.24;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.58 MB
Время: 0.054 c
2-1201456368
viRUS
2008-01-27 20:52
2008.02.24
Нестандартные формы


15-1201252151
tolyan
2008-01-25 12:09
2008.02.24
загрдиск


2-1201695689
Surok
2008-01-30 15:21
2008.02.24
Как сделать DateTimePicker пустым?


2-1201788975
@!!ex
2008-01-31 17:16
2008.02.24
Отменить Win+D


9-1166065606
GameDev
2006-12-14 06:06
2008.02.24
Что случилось с Animiks ?





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский