Основанные указатели (C++) | Microsoft Learn
Twitter LinkedIn Facebook Адрес электронной почты
- Статья
- Чтение занимает 2 мин
Ключевое __based
слово позволяет объявлять указатели на основе указателей (указатели, которые являются смещениями от существующих указателей). Ключевое __based
слово зависит от Корпорации Майкрософт.
Синтаксис
type __based( base ) declarator
Указатели, основанные на адресах указателей, являются единственной формой ключевого слова, допустимой __based
в 32-разрядных или 64-разрядных компиляциях. В 32-разрядном компиляторе Microsoft C/C++ относительный указатель имеет 32-разрядное смещение от 32-разрядной базы указателя. То же ограничение действует и для 64-разрядных сред, где относительный указатель имеет 64-разрядное смещение от 64-разрядной базы указателя.
Указатели на основе указателей, в частности, используются для постоянных идентификаторов, которые содержат указатели. Связанный список, состоящий из указателей на основе указателей, можно сохранить на диск, а затем перезагрузить в другое место в памяти. При этом все указатели останутся действительными. Пример:
// based_pointers1.cpp // compile with: /c void *vpBuffer; struct llist_t { void __based( vpBuffer ) *vpData; struct llist_t __based( vpBuffer ) *llNext; };
Указателю vpBuffer
назначается адрес в памяти, который выделяется на более позднем этапе программы. Связанный список перемещается относительно значения vpBuffer
.
Примечание
Сохранение идентификаторов, содержащих указатели, также можно выполнить с помощью сопоставленных в памяти файлов.
Когда выполняется разыменовывание относительных указателей, база должна быть либо явно указана, либо неявно известна из объявления.
Для совместимости с предыдущими версиями _based
__based
, если не указан параметр компилятора /Za (отключить расширения языка).Пример
В следующем примере демонстрируется изменение относительного указателя путем изменения его базы.
// based_pointers2.cpp // compile with: /EHsc #include <iostream> int a1[] = { 1,2,3 }; int a2[] = { 10,11,12 }; int *pBased; typedef int __based(pBased) * pBasedPtr; using namespace std; int main() { pBased = &a1[0]; pBasedPtr pb = 0; cout << *pb << endl; cout << *(pb+1) << endl; pBased = &a2[0]; cout << *pb << endl; cout << *(pb+1) << endl; }
1 2 10 11
См.
также разделКлючевые слова
alloc_text
Арифметика указателя C++
Мы знаем, что указатели — это адреса переменных в памяти и, как правило, числовые. Вот почему мы можем производить некоторые арифметические вычисления и с указателями. Эти вычисления можно производить так же, как мы делаем с числовыми значениями в математике или программировании. Поэтому мы обсудим некоторые арифметические операции над указателями в нашем учебном руководстве с использованием C ++. Мы использовали систему Ubuntu 20.04, убедившись, что в ней настроен компилятор G ++. Начнем с реализации арифметики указателей в оболочке системного терминала Ubuntu 20.04 с помощью сочетания клавиш Ctrl + Alt + T, используемого на его рабочем столе.
Содержание
- Пример 1
- Пример 2
- Пример 3
- Заключение
Пример 1
Начните первый пример кода C ++, чтобы использовать арифметические операторы «+» для указателей при создании файла. Вы можете создать файл разными способами, но самый простой — использовать «сенсорную» инструкцию. Таким образом, мы попробовали ключевое слово touch вместе с заголовком файла, который нужно сформировать на консоли, и нажали Enter. Файл создается в домашней папке Ubuntu 20.04.
Теперь, чтобы открыть этот только что созданный файл, вы можете использовать любой из встроенных редакторов, поставляемых с Ubuntu 20.04, то есть vim, текстовый редактор или редактор GNU nano. Мы предлагаем вам использовать редактор GNU Nano, поскольку мы использовали его в оболочке, как показано на изображении ниже.
Этот файл «pointer.cc» пока не заблокирован в редакторе. Мы включили заголовочный файл потока ввода-вывода в первую строку, а стандартное пространство имен было использовано во второй строке. Мы инициализировали целочисленную переменную «v» значением 8. В следующей подряд строке мы инициализировали указатель целочисленного типа «p». Этот указатель является адресом переменной «v», поскольку он связан с переменной «v» с помощью знака «&». Это означает, что мы можем изменить адрес изменяемого объекта в любое время. Стандартные операторы cout использовались один за другим. Первый отображает исходный адрес переменной «v», сохраненный как указатель «p».
В следующей строке оператор cout увеличивает адрес указателя на 1 и отображает его. Следующие две строки использовали указатель и увеличивали его значение на 2 и 3. Увеличенные значения были отображены с помощью оператора cout. Код заканчивается здесь. Давайте сначала сохраним код перед выполнением. Для этого используйте Ctrl + S. Вы должны выйти из редактора GNU Nano, чтобы вернуться к терминалу. Для этого воспользуйтесь сочетанием клавиш «Ctrl + X». Это был простейший код C ++ для увеличения указателя с помощью оператора +.
Вернувшись к оболочке, мы должны сделать наш код безошибочным. Для этого используется компилятор C ++. Ключевое слово компилятора «g ++» было использовано вместе с именем файла, который должен быть скомпилирован, например, «pointer.cc». Компиляция прошла успешно, поскольку вы видите, что она ничего не возвращает. Давайте выполним наш безошибочный код с помощью стандартной команды «./a.out». У нас есть 4 разных адреса для переменной «v».
Первый — это исходный адрес «p» переменной «v». Второй увеличивается на 1, третий увеличивается на значение 2, а последний увеличивается на 3. Каждый раз, когда мы выполняем приращение, последние два символа адреса имеют тенденцию изменяться, как показано ниже.
Пример 2
Приведем еще один пример использования оператора декремента для указателя. Итак, мы использовали все тот же старый файл «pointer.cc». Пространство имен и заголовок ввода-вывода используются так же, как и раньше. Другая постоянная целочисленная переменная «s» инициализируется постоянным значением 5. В методе main () мы использовали массив целочисленного типа с именем «v» размера «s» с 5 элементами в нем. Объявлен целочисленный указатель «p». Указатель был привязан к целочисленному массиву «v» с помощью знака «&».
Размер будет начинаться с адреса s-1. Инициализирован цикл for, который начинается с размера 5 и работает в порядке убывания, каждый раз уменьшаясь на 1. Каждый раз, когда цикл for работает, он отображает адрес памяти номера индекса, повторяемого циклом, и значение в конкретном индексе, а также с использованием стандартного оператора cout. «P» показывает адрес индекса, а * P представляет значение этого конкретного индекса. На каждой итерации указатель уменьшался на 1. На этом заканчивается цикл и основная функция.
Сначала скомпилируйте код с помощью компилятора g ++ языка C ++. Он работает успешно, без ошибок. Выполнение осуществляется командой «./a.out». Мы получили результат, как показано ниже. Как видите, у нас есть каждый адрес памяти для определенного индекса, то есть 5,4,3,2,1 в порядке убывания индексов. С другой стороны, мы также получаем значения в каждом конкретном индексе каждый раз, когда цикл повторяется в порядке убывания до последнего значения.
Пример 3
У нас будет новый экземпляр указателей. В этом примере мы будем сравнивать адреса указателей, а также значения, которые они содержат. Таким образом, документ pointer.cc теперь запускается в редакторе GNU Nano. Функция main () была инициализирована после стандартного пространства имен и заголовка потока «io» в файле кода. Он содержит две переменные строкового типа s1 и s2 с совершенно разными строковыми значениями, то есть «Aqsa» и «Yasin».
После этого мы инициализировали две переменные-указатели строкового типа p1 и p2, ограниченные обеими переменными s1 и s2, с помощью символа «&» после знака «=». Это означает, что указатель p1 — это адрес переменной s1, а p2 — адрес переменной s2.
Первое стандартное предложение cout используется для отображения результата сравнения обоих указателей, то есть адресов обеих строковых переменных. Если адреса совпадают, в оболочке будет отображаться 1 как истина, в противном случае 0 как ложь. Второе стандартное предложение cout используется для отображения результата сравнения значений, хранящихся в конкретном адресе указателя. Если значения совпадают, возвращается 1, в противном случае — 0. Программа сравнения на этом заканчивается.
Сначала скомпилируйте свой код C ++ и выполните его. В результате обоих сравнений мы получили 0, т.е. ложь. Это означает, что адреса указателей и значения по этим адресам не совпадают.
Немного изменим код. Откройте тот же файл и обновите строковые значения. Одни и те же строковые переменные s1 и s2 были инициализированы одинаковыми значениями, то есть Aqsa. Остальной код используется без изменений, как и раньше. Сохраните свой код, чтобы получить обновленный результат.
Мы получили 0 как результат сравнения адресов указателей, поскольку обе переменные содержат разные адреса памяти, и 1 как результат сравнения значений, то есть одинаковые значения обеих строк.
Заключение
Мы обсудили арифметические операции, выполняемые над указателями. Также мы использовали арифметические операторы увеличения и уменьшения для указателей. Мы также обсудили бонусные примеры, чтобы проиллюстрировать работу оператора сравнения с двумя разными указателями.
Сборка— В чем практическая разница между регистрами SI и DI?
спросил
Изменено 9 лет, 1 месяц назад
Просмотрено 61к раз
Часть коллектива Intel
Не понимаю в чем разница.
- сборка
- x86
- регистры процессора
0
Когда вы используете такие инструкции, как movsb, si считается регистром нашего источника s , а di — регистром назначения d . Но они оба являются обычными регистрами x86.
Моя сборка немного ржавая, но один индекс источника, другой индекс назначения. Инструкция типа movsb
скопирует байт из ячейки памяти, на которую указывает SI
, и переместит его в ячейку памяти, на которую указывает DI
, а затем увеличит оба значения, поэтому, если вы хотите скопировать байт, хранящийся в SI+1
DI+1
требуется только дополнительная инструкция movsb. SI
означает исходный индекс. Исходный индекс используется в качестве указателя на текущий символ, считываемый в строковой инструкции (LODS, MOVS или CMPS). Исходный индекс также доступен в качестве смещения для добавления Bx или Bp при косвенной адресации.
пример:
MOV [Bx + SI], Ax
Эта инструкция копирует содержимое Ax в ячейку памяти, адрес которой представляет собой сумму Bx и SI.
DI
означает индекс назначения, используемый в качестве указателя на текущий записываемый или сравниваемый символ в строковой инструкции.
Он также доступен как смещение, как и SI.
, как сказано выше, di обозначает целевой индекс, а si обозначает исходный индекс, когда мы хотим переместить данные из памяти, мы используем si, например, mov ax,[si]. и когда мы хотим переместить данные в память, мы используем di. например, mov [di],ax
оба являются 16-битными регистрами и не могут быть разделены на 8-битные
1
Зарегистрируйтесь или войдите в систему
Зарегистрируйтесь с помощью Google
Зарегистрироваться через Facebook
Зарегистрируйтесь, используя электронную почту и пароль
Опубликовать как гость
Электронная почта
Требуется, но не отображается
Опубликовать как гость
Электронная почта
Требуется, но не отображается
Рабочий пример для указателей на структуры в C
спросил
Изменено 4 года, 7 месяцев назад
Просмотрено 748 раз
Меня смущают указатели на структуры в C, и часть моей проблемы в том, что примеры, которые я нахожу, кажутся неправильными.
В этом примере кода, который я нашел здесь, я все еще получаю ужасную ошибку:
предупреждение: назначение из несовместимого типа указателя
#includeструктура Книга { имя персонажа[10]; внутренняя цена; } основной () { структура Книга а; //Одна структурная переменная структура Книга* ptr; //Указатель типа структуры указатель = &а; структура Книга b[10]; // Массив структурных переменных структура Книга* p; //Указатель типа структуры р = &б; вернуть 0; }
У кого-нибудь есть рабочий пример , на котором я мог бы поучиться?
- c
- указатели
- структура
6
Изменение:
p = &b;
В:
р = б;
Это потому, что b
[уже] является массивом. Итак, b
сам по себе относится ко всему массиву, а результат указывает на первый элемент (т. е. &b[0]
). То, что у вас было, генерирует Book **
вместо Book *
[1].
р = &b[0];
ОБНОВЛЕНИЕ:
[1] Плохо. Это фактически генерирует структуру Book (*)[10]
, которая является указателем на массив фиксированного размера (например, 10) структур Book
, который [немного] отличается от простого указателя Book
. Это добавляет длину массива как часть типа, поэтому сопоставление указателя/типа является более строгим/сложным.
A struct Book (*)[10]
не соответствует [по типу] struct Book *
и не будет соответствовать другому указателю фиксированного размера массива длины (например, struct Book (*)[20]
), даже если базовый тип ( struct Book
) тот же.
Однако после определения разыменование/индексация указателя будет аналогичным.