В функциях семейства printf существуют спецификаторы типа "%p" и "%x".
В 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.