Следующие операторы присваивают указателю физический или виртуальный адрес? - PullRequest
0 голосов
/ 06 сентября 2018

С https://stackoverflow.com/a/2761494/156458

ни C, ни C ++ не предоставляют строго определенной функции, которая позволила бы Вы должны назначить конкретный физический адрес указателю. Так что ваши вопрос о том, "как можно присвоить 0 адрес указателю" формально не имеет ответа. Вы просто не можете назначить конкретный адрес указателю в C / C ++. Тем не менее, в сфере функций, определяемых реализацией, явное преобразование целого числа в указатель предназначено для эффект. Итак, вы сделали бы это следующим образом

uintptr_t address = 0;
void *p = (void *) address;

Обратите внимание, что это не то же самое, что

void *p = 0;

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

Я удивлен, узнав, что void *p = 0 не назначает физический или виртуальный адрес 0, но нулевой указатель void указателю.

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

Вопросы:

  1. в void *p = 0, есть ли неявное преобразование из 0 в void*?

    Является ли неявное преобразование таким же, как явное преобразование (void *)0, т. Е. void *p = 0 совпадает с void *p = (void*) 0?

    Производит ли void *p = (void*) 0 указатель на физический или виртуальный адрес 0 или нулевой указатель void?

  2. Если я использую ненулевое число, например, void *p = 123, есть ли неявное перевод с 123 на void *?

    Является ли неявное преобразование таким же, как явное преобразование (void *) 123?

    или void *p = 123 или void *p = (void *)123 сделает p a указатель на физический или виртуальный адрес 123?

    Если void *p = (void *)123 не может сгенерировать указатель на физический или виртуальный адрес 123, может int addr = 123; void *p = (void *)addr;? Я создаю его, заменив unitptr_t на int в первом примере в цитате.

Спасибо.

Ответы [ 2 ]

0 голосов
/ 06 сентября 2018

TL; DR: Большая часть того, о чем вы спрашиваете, относится к поведению, зависящему от реализации, и языковым расширениям. Обратитесь к документации по вашему компилятору, если у вас есть реальная потребность в таком поведении.

  1. в void *p = 0, есть ли неявное преобразование из 0 в void*?

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

Поскольку литерал 0 является «константой нулевого указателя», потому что инициализаторы выполняют те же преобразования, что и простое присваивание, и потому что простое присваивание имеет специальное положение для назначения констант пустых указателей указателям, да, 0 неявно преобразуется в тип void *. Кроме того, поскольку 0 является константой нулевого указателя, такое преобразование приводит к нулевому указателю типа void *.

Является ли неявное преобразование таким же, как явное преобразование (void *)0, т. Е. void *p = 0 совпадает с void *p = (void*) 0?

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

Да. В C нигде не проводится различия между эффектами конверсий, указанными явно посредством приведения, и автоматическими конверсиями между одними и теми же типами.

Производит ли void *p = (void*) 0 указатель на физический или виртуальный адрес 0 или нулевой указатель void?

Инициализирует p, чтобы содержать нулевой указатель (типа void *). Согласно C, нулевой указатель не указывает на какой-либо объект, и C не имеет смысла в адресах, кроме адресов объектов или функций, поэтому по крайней мере в этом смысле неверно интерпретировать такой указатель как указывающий на какой-либо конкретный адрес. Эффект разыменования такого указателя не определяется C, но он может быть определен некоторыми реализациями - возможно, для попытки получить доступ к объекту по адресу 0.

  1. Если я использую ненулевой номер, например, void *p = 123, есть ли неявное преобразование из 123 в void *?

Эта инициализация не соответствует, но некоторые компиляторы предоставляют неявное преобразование как расширение.

Является ли неявное преобразование таким же, как явное преобразование (void *) 123?

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

void *p = 123 или void *p = (void *)123 сделает p указателем на физический или виртуальный адрес 123?

Это определяется реализацией. Опять же, C не имеет смысла адресов, кроме адресов объектов или функций, и, в частности, он сам отказывается указывать результат преобразования целого числа в тип указателя, за исключением целых чисел, полученных путем преобразования указателя в целое число в первую очередь, и для целочисленных константных выражений со значением 0.

Однако в некоторых реализациях преобразование целого числа (кроме целочисленной константы со значением 0) в указатель приводит к интерпретации целого числа как адреса и преобразованию в указатель на этот адрес, как если бы объект с этим адресом. В размещенной реализации C это обычно будет виртуальный адрес. В автономной реализации это обычно будет физический адрес. Некоторые из реализаций могут распространять это поведение также на целочисленные константы со значением 0, которые могут быть или не быть изначально несоответствующими.

Если void *p = (void *)123 не может сгенерировать указатель на физический или виртуальный адрес 123, может int addr = 123; void *p = (void *)addr;? Я создаю его, заменив unitptr_t на int в первом примере в цитате.

Есть все основания ожидать, что результат явного преобразования переменной int со значением 123 точно такой же, как и при явном преобразовании целочисленной константы со значением 123, но, технически, определение этой реализации может привести к комната для соответствующих компиляторов.

0 голосов
/ 06 сентября 2018

Если вы говорите

char *p = 0x12345;

вы, вероятно, назначите p для указания на адрес 0x12345. Виртуальный или физический адрес мы не можем сказать; это зависит от вашей машины и от того, как она настроена. (Но если ваша машина использует виртуальную память, и если вы пишете обычную пользовательскую программу, то это, безусловно, виртуальный адрес.)

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

char *p = (char *)0x12345;

Это снова назначит p для указания на адрес 0x12345.

Но затем мы подходим к особым случаям. Если вы напишите

char *p = 0;

или

char *p = (char *)0;

вопрос в том, назначили ли вы p для указания адреса 0? И ответ, вероятно, на любой обычной машине, но это не гарантируется, потому что есть специальный случай для нулевых указателей.

Это не значит, что p = 0 не будет назначать p для указания на адрес 0 - дело в том, что может не . На машине, где внутренним представлением нулевого указателя является не все биты-0, присваивание p = 0 установит p в это значение нулевого указателя, и поэтому p будет не указывать на адрес 0.

...