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


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

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

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

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

В Win32 системе на экране будет распечатано:

0018FF20
18FF20

Как видите результаты вывода с использованием "%p" и "%X" весьма схожи. Это схожесть и порождает неаккуратность в коде, что приводит к ошибкам при переносе программы на 64-битную платформу. Наиболее часто вместо "%p" используют "%X" для вывода значения указателя, что приводит к распечатке неверного значения, если объект расположен за пределами младших четырех гигабайт адресного пространства. Рассмотрим соответствующий пример 64-битной программы:

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:

// 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.

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



Найдите ошибки в своем C, C++, C# и Java коде

Предлагаем попробовать проверить код вашего проекта с помощью анализатора кода PVS-Studio. Одна найденная в нём ошибка скажет вам о пользе методологии статического анализа кода больше, чем десяток статей.

goto PVS-Studio;



Найденные ошибки

Проверено проектов
344
Собрано ошибок
12 970

А ты совершаешь ошибки в коде?

Проверь с помощью
PVS-Studio

Статический анализ
кода для C, C++, C#
и Java

goto PVS-Studio;