﻿# Отличие %p от %x

В функциях семейства printf существуют спецификаторы типа "%p" и "%x"\.

* x и X \- вывод шестнадцатеричного числа\. "x" использует маленькие буквы \(abcdef\), "X" большие буквы \(ABCDEF\)\.
* p \- вывод указателя\. Вывод может различаться в зависимости от компилятора и платформы\.

В 32\-битных системах часто один спецификатор используют вместо другого, что на самом деле неверно\. Рассмотрим пример:

```cpp
int a = 10;
int *b = &a;
printf("%p\n",b);
printf("%X\n",b);
```

В [Win32](https://pvs-studio.ru/ru/blog/terms/0054/) системе на экране будет распечатано:

```cpp
0018FF20
18FF20
```

Как видите результаты вывода с использованием "%p" и "%X" весьма схожи\. Это схожесть и порождает неаккуратность в коде, что приводит к ошибкам при переносе программы на 64\-битную платформу\. Наиболее часто вместо "%p" используют "%X" для вывода значения указателя, что приводит к распечатке неверного значения, если объект расположен за пределами младших четырех гигабайт адресного пространства\. Рассмотрим соответствующий пример [64\-битной](https://pvs-studio.ru/ru/blog/terms/0001/) программы:

```cpp
size_t Gb = 1024*1024*1024;
char *a = (char *)malloc(2 * Gb * sizeof(char));
char *b = (char *)malloc(2 * Gb * sizeof(char));
printf("use %%X: a=%X\n", a);
printf("use %%X: b=%X\n", b);
printf("use %%p: a=%p\n", a);
printf("use %%p: b=%p\n", b); 
use %X: a=80000040
use %X: b=40010040
use %p: a=0000000080000040
use %p: b=0000000140010040
```

Значение указателя "b" распечатано некорректно при использовании "%X"\.

Рассмотрим еще один пример\. Хотя этот пример выглядит странно, код который приведен здесь в упрощенном виде, использовался в реальном приложении в подсистеме UNDO/REDO:

```cpp
// Here the pointers were saved in the form of a string
int *p1, *p2;
....
char str[128];
sprintf(str, "%X %X", p1, p2);
// In another function this string was processed
// in this way:
void foo(char *str)
{
  int *p1, *p2;
  sscanf(str, "%X %X", &p1, &p2);
  // The result is incorrect values of pointers p1 and p2.
  ...
}
```

Результатом манипуляций указателями с использованием %X стало некорректное поведение программы на 64\-битной системе\. При этом обратите внимание, что подобные ошибки могут проявляться весьма редко\. Для диагностирования этих и схожих дефектов рационально использовать анализатор [PVS\-Studio](https://pvs-studio.ru/ru/pvs-studio/)\.

## Библиографический список

1. Уроки разработки 64\-битных приложений на языке Си/Си\+\+\. [Урок 10\. Паттерн 2\. Функции с переменным количеством аргументов](https://pvs-studio.ru/ru/blog/lessons/0010/)\. 
1. Wikipedia\. [Printf](https://ru.wikipedia.org/wiki/Printf)\.
1. База знаний\. [Как правильно распечатать значение типа \_\_int64, size\_t и ptrdiff\_t](https://pvs-studio.ru/ru/blog/posts/cpp/k0046/)\.