Что произойдет, если я назначу указателю int адрес переменной с плавающей запятой и наоборот? - PullRequest
2 голосов
/ 11 февраля 2020

Мне было интересно, что произойдет, если я дам указателю int адрес переменной float и наоборот, поэтому я попробовал это сделать, но не мог точно понять, что происходит, поэтому, если кто-нибудь сможет объяснить, я был бы благодарен.

int n = 5;
float f = 1.21;
float *pf = &n;
int *pn = &f;

printf("%p  %p\n", pn, pf);
printf("%p  %p\n", &f, &n);
printf("%d   %f \n", *pn, *pf);
printf("%f   %d \n", n, f);
printf("%d  %f \n", n, f);

Выход:

0xffffcba8  0xffffcbac
0xffffcba8  0xffffcbac
1067114824   0.000000
0.000000   0
5  1.210000

Ответы [ 2 ]

3 голосов
/ 11 февраля 2020

Существует несколько случаев неопределенного поведения в вашем коде:

  • int n = 5;: ОК
  • float f = 1.21;: ОК
  • float *pf = &n; инициализирует указатель со значением указателя другого типа. Стандарт C не дает никаких гарантий ни относительно того, что это делает, ни относительно того, что происходит, когда вы разыменовываете этот указатель. С -Wall -W вы наверняка получите предупреждение об этом, которое вы можете отключить с помощью приведения: float *pf = (float *)&n;, но результат тот же, разыменование указателя имеет неопределенное поведение.
  • int *pn = &f; то же самое как указано выше.
  • printf("%p %p\n", pn, pf); -> вы должны привести указатели как (void *), поскольку %p ожидает void * в качестве аргумента. В некоторых редких системах (старые системы Cray IIR C) указатели на int, float и void могут иметь разные представления, в результате чего этот вызов printf ведет себя неожиданным образом. Используйте это вместо:

    printf("%p  %p\n", (void *)pn, (void *)pf);
    
  • printf("%p %p\n", &f, &n); -> та же проблема. Используйте это вместо:

    printf("%p  %p\n", (void *)&f, (void *)&n);
    

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

  • printf("%d %f \n", *pn, *pf); это правильно, но разыменование указателя имеет неопределенное поведение.
  • printf("%f %d \n", n, f); передача значений типов, отличных от ожидаемых, имеет неопределенное поведение. Вывод, который вы получаете, неверен.
  • printf("%d %f \n", n, f); Этот вывод правильный, и вывод 5 1.210000, как и ожидалось.
1 голос
/ 11 февраля 2020

ответ Чкрли намного лучше, чем мой. Пожалуйста, примите его ответ повторно.


Вы не должны злоупотреблять указателями и объектами - даже не по причинам любопытства. Результаты команд 1., 2. и 5. printf являются правильными, но результаты команд 3. и 4. printf являются продуктами неопределенного поведения, поэтому никто не может их объяснить.

Для получения дополнительной информации о неопределенном поведении: Неопределенное, неопределенное и определяемое реализацией поведение

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