Мне любопытно посмотреть, как вы справились со своими временами, потому что обычно двойное косвенное обращение не должно стоить намного больше, чем одно косвенное - разница должна быть крошечной.
Однако если в этом случае ваш двойной указатель стоит больше, чем один, есть две вероятные причины:
(1) конвейер задержка.
Современные ЦП спроектированы таким образом, что, хотя они могут выполнять (как минимум) одну инструкцию за цикл, большинству команд требуется более одного цикла.То есть вы могли бы запускать одну новую операцию «добавления» каждый тактовый цикл, но результаты любого данного добавления могут быть недоступны, скажем, до четырех циклов после его запуска.Если вы попытаетесь использовать результат операции до того, как она будет готова, это вызовет нечто, называемое опасность данных , что просто означает, что процессор должен ждать, пока результат не будет готов, прежде чем он сможет сделать что-то еще с ним,В вашем случае компьютер должен выполнить две операции «загрузки» последовательно, при сборке что-то вроде:
load r3, str ; load the value of "str" (an address of a pointer) into register three
load r4, r3 ; load the thing at the address stored in r3 and put it in r4.
; in this case, r3 points at a char *, so the thing in r4 is also an address.
load r5, r4 ; load the thing at address r4 and put it in r5. that is your char.
В этом случае вы можете видеть, что третья загрузка зависит от результата второй загрузки, который зависит от первого.Если для выполнения второй загрузки требуется более одного цикла (что почти всегда происходит - обычно пять циклов соответствуют задержке в лучшем случае), тогда третья загрузка должна ждать.Там будет "пузырь" в трубопроводе.Если str является глобальным, то у вас на одну нагрузку меньше, а значит, на один пузырь меньше.
(2) Кэш данных
Современная память настолько велика, и процессорынастолько быстры, что доступ к основному ОЗУ из ЦП может занять много-много циклов.Чтобы ускорить это, центральные процессоры хранят меньшее подмножество основной памяти локально в кеше, потому что если вы используете переменную x , вполне вероятно, что вы собираетесь использовать x или что-то подобное x снова.Доступ к кешу быстрый, но он хранит только небольшой объем данных - обычно от 256 до 4 Мб, как правило.Если операция загрузки пытается получить доступ к адресу, который не находится в кеше, то процессор должен пройти весь путь до основной оперативной памяти, чтобы извлечь его, и операция загрузки может занять 1000 циклов вместо пяти.
Таким образом, если доступ к ** str означает два пропуска кэша вместо одного, тогда разница может быть значительной.
Ульрих Дреппер написал очень хорошее объяснение всех этих проблем в своей статье Что каждый программист должен знать о памяти .