HOME FORUMS MEMBERS RECENT POSTS LOG IN  
× Авторизация
Имя пользователя:
Пароль:
Нет аккаунта? Регистрация
Баннер 1   Баннер 2
НОВЫЕ ТОРГОВАЯ НОВОСТИ ЧАТ
loading...
Скрыть
Вернуться   ANTICHAT > ПРОГРАММИРОВАНИЕ > Общие вопросы программирования
   
Ответ
 
Опции темы Поиск в этой теме Опции просмотра

  #1  
Старый 30.03.2023, 20:14
ya_noob
Познающий
Регистрация: 26.10.2022
Сообщений: 57
С нами: 1870038

Репутация: 8
По умолчанию

В языке C и C++ существуют указатели. Естественно понятно, что они указывают на определенную ячейку памяти.

C++:





Код:
// Я знаю что ссылки могут обьявляться следующим образом.
int
x
=
1
;
int
*
ax
=
&
x
;
// Но меня смутило следующее.
int
&
addr
=
*
(
int
*
)
0xBAB230
;
// интовая ссылка addr содержит в себе адрес памяти, который сначала обьявляется как указатель, а затем разименовывается?
// Я хочу понять, правильно ли я это понимаю. *(int*)0xBAB230 - int* 0xBAB230 - это указатель указателя, который потом разименовывается (благодаря * спереди) и получается что-то вроде int& addr = b, где b = 0xBAB230, а *b = значение этого адреса? Или нет?
// В ИТОГЕ: int& addr = *(int*)0xBAB230 == int& addr = b; addr = *b; *(int*)0xBAB230 - адрес адреса, который затем разименовывают и получается адрес в нужном формате?
// Скорее всего я все не так понимаю. Напишите пожалуйста, что это за конструкция *(int*), как ее можно по другому написать, и почему именно в таком виде "*(int*)".
 
Ответить с цитированием

  #2  
Старый 30.03.2023, 20:43
ARMOR
Флудер
Регистрация: 02.02.2019
Сообщений: 5,070
С нами: 3831395

Репутация: 183


По умолчанию

Цитата:
Сообщение от voodushevlen  

C++:





Код:
// Скорее всего я все не так понимаю. Напишите пожалуйста, что это за конструкция *(int*), как ее можно по другому написать, и почему именно в таком виде "*(int*)".

C++:





Код:
*
reinterpret_cast

(
0xBAB230
)
;


А *(int*) - это вроде как старый вариант переобразования типов
 
Ответить с цитированием

  #3  
Старый 30.03.2023, 20:47
Digger Man52
Познавший АНТИЧАТ
Регистрация: 14.07.2019
Сообщений: 1,097
С нами: 3596877

Репутация: 183


По умолчанию

Да, *(int*)0xBAB230 это разыменование указателя на int, *(int*) используется для приведения указателя на void к указателю на int

Цитата:
Сообщение от voodushevlen  

C++:





Код:
// В ИТОГЕ: int& addr = *(int*)0xBAB230 == int& addr = b; addr = *b; *(int*)0xBAB230 - адрес адреса, который затем разименовывают и получается адрес в нужном формате?

Мы разыменовываем 0xBAB230 , и присваиваем это значение, addr и получаем addr = *(int*)0xBAB230 и addr = b;

Альтернативный вид это конструкции, будет выглядеть как







C++:





Код:
*
reinterpret_cast

(
0xBAB230
)


*reinterpret_cast(0xBAB230) возвращает значение переменной, находящейся по адресу 0xBAB230
 
Ответить с цитированием

  #4  
Старый 31.03.2023, 01:54
EclipsedFlow
Познавший АНТИЧАТ
Регистрация: 18.09.2017
Сообщений: 1,044
С нами: 4553429

Репутация: 153


По умолчанию

Цитата:
Сообщение от ARMOR  

C++:





Код:
*
reinterpret_cast

(
0xBAB230
)
;


А *(int*) - это вроде как старый вариант переобразования типов
Он не старый, а CИ-шный вариант преобразования типов.

Для языка C++ нужно/можно приводить static_cast, const_cast, dynamic_cast, reinterpret_cast. Так и СИ-шным вариантом выше.

Код:





Код:
// Как я понимаю мы копируем значение переменной из адреса предварительно приведя к типу указателя int и последующим его разыменованием.
int addr = *(int*)0xBAB230;

// А если добавить в перед нашей переменной амперсанд(ссылку)[&] то мы не копируем, а берем ссылку переменной с адреса
int& addr = *(int*)0xBAB230;

// Если что подправьте если не правильно понимаю
 
Ответить с цитированием

  #5  
Старый 31.03.2023, 06:50
kin4stat
Флудер
Регистрация: 06.11.2017
Сообщений: 2,759
С нами: 4483143

Репутация: 183


По умолчанию

C++:





Код:
int
&
addr
=
*
(
int
*
)
0xBAB230
;


Код:
(int*)
- C style cast, в данном случае эквивалентный код выглядит так:

C++:





Код:
int
&
addr
=
*
(
reinterpret_cast

(
0xBAB230
)
)
;


Код:
0xBAB230
- integer literal, интерпретируется как число.

Код:
reinterpret_cast
- преобразование числа 0xBAB230 типа int в указатель на int. Фактически данная конструкция ничего не делает.

В данном случае она нужна для преобразования числа в указатель, на уровне системы типов языка.

В результате этого выражения получается указатель, который указывает на адрес
Код:
0xBAB230
Далее идет
Код:
*(reinterpret_cast(...));
Разыменование указателя дает lvalue ссылку на тип под указателем.

Фактически работает примерно так: звездочка около типа заменяется амперсандом(ссылкой)

Код:
*(T*) -> (T&)
, где T - произвольный тип

После этого ссылка на
Код:
int
присваивается переменной addr.

Если говорить очень грубо - ссылка это всегда разыменованный указатель, который не может быть НЕ ИНИЦИАЛИЗОВАН и НЕ МОЖЕТ БЫТЬ ИЗМЕНЕН(сам адрес ссылки)

В результате выражения, получается ссылка типа
Код:
int
на адрес
Код:
0xBAB230
. Любые операции с этой переменной будут взаимодействовать с ячейкой памяти по адресу
Код:
0xBAB230
как с целым числом(
Код:
int'ом
)
 
Ответить с цитированием

  #6  
Старый 31.03.2023, 16:10
san0
Постоянный
Регистрация: 15.12.2013
Сообщений: 412
С нами: 6530249

Репутация: 133
По умолчанию

Цитата:
Сообщение от kin4stat  

Разыменование указателя дает lvalue ссылку на тип под указателем.

Фактически работает примерно так: звездочка около типа заменяется амперсандом(ссылкой)

Код:
*(T*) -> (T&)
, где T - произвольный тип
Не, что-то не так. Поправьте, если неправильно понял.

Унарный оператор * над указателем на T это T (lvalue).

Ссылка на T (т.е. T&) может быть инициализирована объектом типа T (не T&).

Так как любое lvalue явно идентифицируется в памяти, обращение к ссылке под капотом будет ссылаться к адресу, в котором расположен этот lvalue

Цитата:
Сообщение от voodushevlen  

В языке C и C++ существуют указатели
Вам уже много написали всего, поэтому попробую немного вокруг описать, может это поможет

Ссылочный тип данных - это новояз именно C++. Сохраняя общую семантику указателей (в частности, техническую часть), он становится более безопасным и предпочитаемым типом нежели указатель, так как:
  • Ссылка не может быть неопределенной/нулевой/указывать на невалидный объект. Представьте, как C++ обошел все языки, в которых только недавно решили null-safety вводить;
  • Ссылка четко определена как немутабельная в отличии от указателя (нельзя поменять куда она ссылается). Кроме того, не бывает ссылки на ссылку, массив ссылок и прочих головоломок;
  • Ссылка исходя из правил и ограничений выше указанных имеет определенное поведение, из разряда, что ссылки должны быть инициализированы для членов класса, что константная ссылка продлевает срок жизни объекта и так далее.
  • Удобство использования, так как не нужно постоянно разыменовывать его и прочие мелочи.
Надеюсь не будет звучать тупо, но в целом при использовании ссылок не нужно беспокоится об адресах, ссылки - это о значениях, которые расположены по адресам, указатели - наоборот, об адресах, которые указывают на значения.

Окей, предположим, что мы хотим пользоваться этой вашей крутой ссылкой хваленой, но нужно это для адреса 0xBAB230:

C++:





Код:
// ** давайте не будет придираться к тому, что не всегда sizeof(int) == sizeof(int*)
// да и вообще адрес памяти - не совсем верный термин, так как это не всегда линейное пространство, c/c++ - это не только x86/arm
// сохраним желаемый адрес памяти в переменной. Уже выше говорили, что 0xBAB230 - числовой литерал, значит и тип переменной int
int
address_as_int
=
0xBAB230
;
// так как у нас адрес, то объявить ссылку мы не можем, нужно получить значение по этому адресу, для чего будем пользоваться указателями
// чтобы представить число как адрес в памяти, его необходимо преобразовать в указатель
int
*
address_as_pointer
=
(
int
*
)
address_as_int
;
// здесь есть 3 варианта
// *address_as_pointer   -> разыменование указателя. Получит то, куда он ссылается. Т.е. значение по адресу 0xBAB230
// address_as_pointer    -> адрес, куда указывает указатель, т.е. 0xBAB230
// &address_as_pointer   -> адрес самого указателя address_as_pointer, это такая же переменная как и все другие,
//                          просто содержит в себе адрес, а значит должна где-то находиться в памяти
// как уже подчеркнули, чтобы инициализировать ссылку, нужно передать ей значение, т.е. разыменовать указатель
// если указатель неверный, то "ошибка" случится на этапе разыменовывания указателя, но не инициализации ссылки
int
&
reference
=
*
address_as_pointer
;
// теперь можно пользоваться, "разыменовывание" ссылки сделает сам компилятор,
// причем с гарантией того, что он указывает на инициализированный объект
// reference = 0;
// а вот с указателем проблемы, ведь нет гарантии, что address_as_pointer указывает на валидный адрес (даже если бы сделали его константным),
// до момента его разыменовывания это может быть бомба замедленного действия.
// Каждое разыменовывание выполняется самостоятельно со всеми рисками
// *address_as_pointer = 0;
 
Ответить с цитированием

  #7  
Старый 31.03.2023, 17:33
SR_team
Флудер
Регистрация: 26.10.2013
Сообщений: 4,924
С нами: 6603505

Репутация: 183


По умолчанию

Ссылка это обертка над указателем. Для компилятора запись

Код:
int &x = *(int*)0x123
Означает следующее:

Код:
int *x = &(*(int*)0x122)
Тут & и * взаимоуничтожаются, и остается:

Код:
int *x = (int*)0x123
Далее, когда ты пишешь в x, компилятор подставляет * и получается, что ты пишешь в *x = 1337
 
Ответить с цитированием

  #8  
Старый 31.03.2023, 18:35
kin4stat
Флудер
Регистрация: 06.11.2017
Сообщений: 2,759
С нами: 4483143

Репутация: 183


По умолчанию

Цитата:
Сообщение от san0  

Унарный оператор * над указателем на T это T (lvalue).
Ссылка на T (т.е. T&) может быть инициализирована объектом типа T (не T&).
Так как любое lvalue явно идентифицируется в памяти, обращение к ссылке под капотом будет ссылаться к адресу, в котором расположен этот lvalue
Ты путаешь категорию значения с типом ссылки. Разыменование дает lvalue reference, lvalue reference сам по себе является lvalue
 
Ответить с цитированием

  #9  
Старый 31.03.2023, 21:12
san0
Постоянный
Регистрация: 15.12.2013
Сообщений: 412
С нами: 6530249

Репутация: 133
По умолчанию

Цитата:
Сообщение от kin4stat  

Ты путаешь категорию значения с типом ссылки. Разыменование дает lvalue reference, lvalue reference сам по себе является lvalue
C++:





Код:
int
&
addr
=
*
(
int
*
)
0xBAB230
;


Ссылка - это левая часть, ее тип - lvalue reference to int.

Справа - выражение, которое после вычисления *((T*)ptr) будет lvalue выражением, но типа T, а не lvalue reference T&

Даже явный каст к T& ничего не дает, он все равно неявно преобразуется к T и инициализирует ссылку, как и сказано в стандарте

C++:





Код:
int
a
=
1
;
int
*
ptr
=
(
int
*
)
&
a
;
// даже не ссылку можно инициализировать при помощи lvalue выражения (static_cast к lvalue reference это lvalue) типа lvalue reference (int&)
int
val
=
static_cast

(
*
ptr
)
;
int
&
ref
=
static_cast

(
*
ptr
)
;


Где стандартом обозначено, что *(T*) == (T&) т.е. разыменование указателя равняется T& а не T?
 
Ответить с цитированием

  #10  
Старый 01.04.2023, 14:21
kin4stat
Флудер
Регистрация: 06.11.2017
Сообщений: 2,759
С нами: 4483143

Репутация: 183


По умолчанию

Цитата:
Сообщение от san0  

C++:





Код:
int
&
addr
=
*
(
int
*
)
0xBAB230
;


Ссылка - это левая часть, ее тип - lvalue reference to int.
Справа - выражение, которое после вычисления *((T*)ptr) будет lvalue выражением, но типа T, а не lvalue reference T&

Даже явный каст к T& ничего не дает, он все равно неявно преобразуется к T и инициализирует ссылку, как и сказано в стандарте

C++:





Код:
int
a
=
1
;
int
*
ptr
=
(
int
*
)
&
a
;
// даже не ссылку можно инициализировать при помощи lvalue выражения (static_cast к lvalue reference это lvalue) типа lvalue reference (int&)
int
val
=
static_cast

(
*
ptr
)
;
int
&
ref
=
static_cast

(
*
ptr
)
;


Где стандартом обозначено, что *(T*) == (T&) т.е. разыменование указателя равняется T& а не T?
Да, ты прав, я там ошибся.

*ptr дает lvalue на T, и уже в момент присвоения категория lvalue материализуется в тип, и там получается T&
 
Ответить с цитированием
Ответ





Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT ™ © 2001- Antichat Kft.