Functions belonging to the printf function family have the type specifiers "%p" and "%x".
One specifier is often used instead of another on 32-bit systems, but it is a mistake. Here is an example:
int a = 10;
int *b = &a;
printf("%p\n",b);
printf("%X\n",b);
On a Win32 system, the following result will be printed:
0018FF20
18FF20
As you may see, the output results for "%p" and "%X" are rather similar. This similarity leads to inaccuracy in the code and this, in turn, results in errors occurring when you port a program to a 64-bit platform. Most often it is "%X" that is used instead of "%p" to output the value of a pointer, and this results in printing of an incorrect value if the object is situated outside the four less significant Gbytes of the address space. Let us consider the corresponding 64-bit version of this program:
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
The pointer value "b" is printed incorrectly when using "%X".
Here is one more example. Although it looks strange, the code given here in an abridged form was used in a real application in the UNDO/REDO subsystem:
// 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.
...
}
Manipulation with the pointers using "%X" resulted in an incorrect program behavior on a 64-bit system. Note that such errors might occur very rarely. To diagnose these, and other similar flaws, it is a good idea to use the analyzer PVS-Studio.
0