%p
означает «напечатать указатель». Вы должны передать ему указатель, который был преобразован в void *
.%x
означает «вывести unsigned int
в шестнадцатеричном формате». Вы должны передать ему unsigned int
;неверно передавать указатель.
Предположим, у нас есть:
char *pointer = "Hello";
char array[] = "World";
Тогда в:
printf("%p", (void *) pointer);
printf("%p", (void *) array);
Значение pointer
будетнапечатан некоторым образом, определяемым реализацией.(Он должен показать вам адрес, который хранится в pointer
.)
Во втором printf
массив array
будет преобразован в указатель на свой первый элемент, и значение этогоуказатель будет напечатан в соответствии с реализацией.
Обратите внимание, что я вставил приведение к (void *)
.Это правильный способ использования %p
.
In:
printf("%x", (unsigned) pointer);
printf("%x", (unsigned) array);
Значение pointer
будет преобразовано в unsigned int
.Результат этого преобразования определяется реализацией.Это не должно удивлять, но может отличаться от того, что вы видите с %p
.Кроме того, unsigned int
может быть слишком узким, чтобы содержать полное значение указателя, и в этом случае некоторая информация будет потеряна.
После этого преобразования первый оператор напечатает значение в шестнадцатеричном формате (безведущий «0x», тогда как использование %p
часто включает ведущий «0x»).Второй оператор снова преобразует array
в указатель на свой первый элемент, затем преобразует его в unsigned int
, а затем выводит его в шестнадцатеричном формате.
Если unsigned int
достаточно широк, это возможно,даже не исключено, что значения, напечатанные этим методом, будут отображать те же шестнадцатеричные значения, как показано методом %p
, но вы не можете полагаться на это.
Обратите внимание, что при печати их с использованием %x
без преобразованияк unsigned
имеет поведение, не определенное стандартом C - ошибка передавать указатель для спецификации %x
.Вы должны преобразовать это сначала.Ваш исходный код без преобразования может привести к тому, что значение будет напечатано из некоторых произвольных данных, не связанных с указателем, или оно могло вызвать прерывание вашей программы, или оно могло бы распечатать правильный адрес, или это могло бы сделатьчто-то еще - поведение не определено.
In:
printf("%x", (unsigned) &pointer);
printf("%x", (unsigned) &array);
Адрес pointer
, а не его значение, будет преобразован в unsigned int
и затем напечатан вшестнадцатеричное.Это почти наверняка будет отличаться от результата печати pointer
.
Для &array
адрес массива будет преобразован в unsigned
.В отличие от предыдущих операторов, array
не преобразуется в указатель на его первый элемент.Это потому, что &
является специальным оператором, который подавляет это преобразование.Он возвращает адрес массива.
Адрес массива «совпадает» с адресом его первого элемента, потому что в памяти массив начинается там, где начинается его первый элемент.Однако указатели могут иметь разные представления, и возможно, что преобразование &array
в unsigned int
может дать другое значение, чем преобразование array
в unsigned int
.Тем не менее, в большинстве реализаций C они выдают одно и то же значение, поэтому вы увидите тот же результат для printf("%x", (unsigned) &array);
, что и для printf("%x", (unsigned) array);
.