Разница в ч / б получении адреса переменной с использованием% p и% d - PullRequest
0 голосов
/ 30 июня 2018

Вот пример

#include <stdio.h>

int main()
{
    int a;
    printf("%d\n",&a);
    printf("%p\n",&a);

    return 0;
}

====== Вывод =======

-2054871028                                                                                                                      
 0x7ffd8585280c

Эти два адреса указывают на один и тот же адрес в ОЗУ?

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

Ответы [ 2 ]

0 голосов
/ 30 июня 2018

Когда вы берете адрес переменной a, записывая &a, вы действительно генерируете указатель на a.

%p предназначен для печати указателей. Вы должны использовать %p для печати указателей.

%d не предназначен для печати указателей. Он пытается напечатать их значения в виде десятичного числа со знаком, что может сбить с толку (как вы видели), и он может не распечатать все значение на машине, где указатели больше целых. (Например, если вы попытаетесь напечатать указатели с% d в большинстве «64-битных» сред, вы можете получить даже более странные результаты - и это может быть частью того, что здесь произошло.)

Это простая ошибка. Хорошие компиляторы должны предупредить вас об этом. Мой говорит: «предупреждение: формат указывает тип« int », но аргумент имеет тип« int * »».

Но да, и 0x7ffd8585280c, и -2054871028 действительно "указывают на один и тот же адрес в ОЗУ", потому что они оба имеют одинаковый номер, один и тот же адрес. (Ну, они пытаются использовать один и тот же адрес. См. Сноску ниже.)

Я не уверен, что вы подразумеваете под "И как я могу получить значение". Вы пытаетесь получить значение указателя или значение, на которое указывает указатель?

Вы уже получили значение указателя - это адрес 0x7ffd8585280c. И поскольку мы знаем, что она указывает на переменную a, мы также знаем значение, на которое она указывает. Все будет немного яснее, если мы сделаем это так:

int a = 5;
int *ip = &a;
printf("value of pointer: %p\n", ip);
printf("pointed-to value: %d\n", *ip);

Без явной переменной-указателя ip мы могли бы написать

int a = 5;
printf("value of pointer: %p\n", &a);
printf("pointed-to value: %d\n", *&a);

Но это довольно глупо, потому что последняя строка эквивалентна гораздо более простой

printf("pointed-to value: %d\n", a);

(Взятие адреса переменной с помощью &, а затем захват содержимого указателя с помощью * - это не вариант: это очень похоже на написание a + 1 - 1.)


Сноска. Я сказал, что 0x7ffd8585280c и -2054871028 - это одно и то же число, но это не так, они просто пытаются быть. 0x7ffd8585280c на самом деле -140748133160948, а -2054871028 на самом деле 0x8585280c, что является младшими 8 цифрами 0x7ffd8585280c. Похоже, %p на вашем компьютере по умолчанию печатает указатели как 48-битные значения. Я был удивлен этим, но потом понял, что мой Mac делает то же самое. Почему-то я никогда этого не замечал.

0 голосов
/ 30 июня 2018

%d спецификатор формата используется для вывода десятичного целого числа со знаком.

Из стандарта C # 7.21.6.1p8

д, я
Аргумент int преобразуется в десятичный знак со знаком в стиле [-] dddd. Точность определяет минимальное количество отображаемых цифр; если конвертируемое значение может быть представлено меньшим количеством цифр, оно расширяется начальными нулями. Точность по умолчанию равна 1. Результат преобразования нулевого значения с точностью до нуля не содержит символов.

%p печатает указатель.

Из стандарта C # 7.21.6.1p8

р
Аргумент должен быть указателем на void. Значение указателя преобразуется в последовательность печатных символов, определяемым реализацией способом . [Акцент мой]

Это утверждение

    printf("%d\n",&a);

приводит к неопределенному поведению, поскольку %d недопустимо для печати указателя.

Из стандарта C # 7.21.6.1p9

Если спецификация преобразования недопустима, поведение не определено. 282) Если какой-либо аргумент имеет неправильный тип для соответствующей спецификации преобразования, поведение не определено.

...