Static_cast'd значение указателя

В текущем проекте стандарта (и C++ 17) это написано о static_casting void *:

A prvalue of type “pointer to cv1 void” can be converted to a prvalue of type “pointer to cv2 T”, where T is an object type and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. If the original pointer value represents the address A of a byte in memory and A does not satisfy the alignment requirement of T, then the resulting pointer value is unspecified. Otherwise, if the original pointer value points to an object a, and there is an object b of type T (ignoring cv-qualification) that is pointer-interconvertible with a, the result is a pointer to b. Otherwise, the pointer value is unchanged by the conversion.

Интересно, а какая разница, является преобразование взаимопреобразуемым по указателю или нет? Есть ли случай, когда приведение void * к чему-то, что можно преобразовать по указателю, действительно изменяет значение указателя? В чем смысл этого различия?

Для полноты стрелочный переводчик:

Two objects a and b are pointer-interconvertible if:

  • (4.1) they are the same object, or
  • (4.2) one is a union object and the other is a non-static data member of that object ([class.union]), or
  • (4.3) one is a standard-layout class object and the other is the first non-static data member of that object, or, if the object has no non-static data members, any base class subobject of that object ([class.mem]), or
  • (4.4) there exists an object c such that a and c are pointer-interconvertible, and c and b are pointer-interconvertible.

If two objects are pointer-interconvertible, then they have the same address, and it is possible to obtain a pointer to one from a pointer to the other via a reinterpret_­cast.

Наверное связанные с

Joseph D. 10.07.2018 08:07

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

JHBonarius 10.07.2018 08:21
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
9
2
557
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Is there a case, when casting a void * to something pointer-interconvertible actually changes the pointer value?

Нет, в стандарте четко указано

If two objects are pointer-interconvertible, then they have the same address

What is the intent of this distinction?

Я думаю, различие заключается не в значении указателя, а в его семантике. Важная часть заключается в том, что вы получаете указатель на объект b (который взаимно перекрывается с указанным исходным объектом). Это более сильная и конкретная гарантия, чем «исходное значение остается неизменным», даже если в этом случае исходное значение также остается неизменным.

Более сильная гарантия: результирующий указатель указывает на реальный объект (а не только на адрес в памяти)

A более конкретная гарантия: этот объект указан: это объект b, который является указателем, взаимозаменяемым с исходным объектом, на который указывает указатель.

Я не думаю, что «результат - указатель на b» подразумевает «указатель указывает на реальный объект». Указатель объекта может быть явно преобразован в указатель объекта другого типа.

llllllllll 10.07.2018 08:28

@liliscent ваша цитата про reinterpret_cast

bolov 10.07.2018 08:31

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

llllllllll 10.07.2018 08:34

@liliscent, это именно моя точка зрения. И цитата дает дополнительную гарантию: «результат - указатель на b».

bolov 10.07.2018 08:36

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

geza 10.07.2018 08:39

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

Richard Critten 10.07.2018 08:42

Это имеет смысл, «указатель на b» действительно подразумевает реальный объект b. +1

llllllllll 10.07.2018 08:52

@geza a) В целях сборки мусора б) В целях оптимизации они разные.

Passer By 10.07.2018 08:55

@PasserBy: означает ли это, что каким-то образом я могу создать указатель A * на адрес, где объект A существует, но он указывает не на объект, а только на адрес?

geza 10.07.2018 08:59

@PasserBy: хм, может мой последний вопрос касается этого: stackoverflow.com/questions/47653305/…. Странно признать, что указатель указывает на адрес объекта, но он указывает не на сам объект, а только на его адрес.

geza 10.07.2018 09:03

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

Passer By 10.07.2018 09:14

Означает ли это, что вам разрешено создавать объекты (POD) с помощью static_cast (при условии, что вы позаботитесь о выравнивании)?

rustyx 10.07.2018 09:27

@rustyx Нет. Это обсуждалось много раз.

Passer By 10.07.2018 09:30

Спасибо, болов! Я поддержал ваш ответ, но я приму ответ xskxzr, потому что он / она разъяснил, как следует думать об указателях. Я тоже понимаю ваш ответ, но именно ответ xskxzr открыл мне глаза.

geza 10.07.2018 11:11

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

rustyx 10.07.2018 11:12

@rustyx: в C++ 14 это преобразование не было определено. Теперь говорят, что такие преобразования не меняют значение указателя. Так что я думаю, что у этого предложения есть свое место.

geza 10.07.2018 11:17
Ответ принят как подходящий

Вы можете неправильно понять термин «значение указателя». Термин определен в [basic.compound] / 3:

Every value of pointer type is one of the following:

  • a pointer to an object or function (the pointer is said to point to the object or function), or

  • a pointer past the end of an object ([expr.add]), or

  • the null pointer value ([conv.ptr]) for that type, or

  • an invalid pointer value.

A value of a pointer type that is a pointer to or past the end of an object represents the address of the first byte in memory ([intro.memory]) occupied by the object or the first byte in memory after the end of the storage occupied by the object, respectively.

Таким образом, вы можете видеть, что термин «значение указателя» в стандарте - очень абстрактный термин. Даже если два значения указателя представляют один и тот же адрес, они могут иметь разные значения. Пример в cppreference прекрасно демонстрирует концепцию «значения указателя»:

struct S1 { int a; } s1;
struct S2 { int a; private: int b; } s2; // not standard-layout
union U { int a; double b; } u = {0};
int arr[2];
 
int* p1 = reinterpret_cast<int*>(&s1); // value of p1 is "pointer to s1.a" because s1.a
                                       // and s1 are pointer-interconvertible
 
int* p2 = reinterpret_cast<int*>(&s2); // value of p2 is unchanged by reinterpret_cast and
                                       // is "pointer to s2". 
 
int* p3 = reinterpret_cast<int*>(&u);  // value of p3 is "pointer to u.a": u.a and u are
                                       // pointer-interconvertible
 
double* p4 = reinterpret_cast<double*>(p3); // value of p4 is "pointer to u.b": u.a and u.b
                                            // are pointer-interconvertible because both
                                            // are pointer-interconvertible with u
 
int* p5 = reinterpret_cast<int*>(&arr); // value of p5 is unchanged by reinterpret_cast and
                                        // is "pointer to arr"

"формально описать строгие правила псевдонима" Имеют ли так называемые "строгие правила псевдонима" какую-то формальную цель?

curiousguy 11.07.2018 05:27

@curiousguy Этот ответ показывает, как эти правила приносят пользу компилятору / оптимизатору.

xskxzr 11.07.2018 06:02

@xskxzr: ваш ответ мне очень помог. Он должен стать более заметным ... Могу я вас спросить, как вы узнали точную семантику указателей? Учитель? Книга? Читаете и интерпретируете стандарт?

geza 29.07.2018 21:30

@geza Это одно из изменений в C++ 17. Я обратил внимание на эти изменения, поэтому знаю это семантическое изменение.

xskxzr 30.07.2018 05:28

Другие вопросы по теме