可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
What is the string format for intptr_t
and uintptr_t
which is valid for both the 32 and 64 bit architecture .
EDIT
warning: format ‘%x’ expects type ‘unsigned int’, but argument 2 has type "AAA"
This is the warning i am getting in 64 bit but not in 32 bit.
intptr_t AAA
回答1:
That would be the following macros from inttypes.h
:
For printf
:
PRIdPTR PRIiPTR PRIoPTR PRIuPTR PRIxPTR PRIXPTR
For scanf
:
SCNdPTR SCNiPTR SCNoPTR SCNuPTR SCNxPTR
Usage example:
uinptr_t p = SOME_VALUE;
printf("Here's a pointer for you: %" PRIxPTR "\n", p);
回答2:
I think you should consider using the 'z' modifier. This will convert anything that corresponds to a size_t og ssize_t, and I have found that it works with (u)intptr_t as well.
For example:
intptr_t ip = ...;
printf("ip = %zd\n", ip);
回答3:
I think even long int
is unsafe, and you should try long long int
, which must exist because you are working on a 64-bit architecture and you have intptr_t
already.
On some 64-bit architectures (I think Microsoft Windows would be so), long int
may be kept in 32-bit width, to satisfy the MS-DOS-age assumption that short int
is always 16-bit and long int
is always 32-bit.
Even on those platforms with 32-bit long int
, printf("%llx", (unsigned long long)AAA);
would work. And you should consider more preferrable form printf("%jx", (uintmax_t)AAA);
if possible.
Note that for some old compilers you might need to use "%Lx"
(for GNU C, with casting to unsigned long long
) or "%I64x"
(for Visual C++, with casting to __uint64
) for 64-bit integers.
P. S.
%p
may not be good in this case, because %p
may print the bareword 0x
before the hexadecimals and/or may print a zero-padded value. If the both is applied, for example, the code printf("%p\n", (void*)16);
will print 0x00000010
on 32-bit platforms and 0x0000000000000010
on 64-bit platforms; the poster should have hoped just 10
be printed.
回答4:
%p
should work as a replacement for %x
, since uintptr_t
is defined to be an unsigned integer with the same size as a pointer on the platform.
EDIT: Unfortunately, at least on my compiler you have to cast the variable to (void *). However, I think it is safe to cast uintptr_t to a pointer.
回答5:
I'm compiling some code in an environment which for some reason does not have the PRI.PTR
macros defined in inttypes.h
, and in which intptr_t
is defined as int
in 32 bit and long int
in 64 bit.
I hacked around the warnings by using a %li
format specifier and casting the variables to long int
in the printf
parameters. This is safe within this environment because an intptr_t
can never be longer than a long int
, as described above.
I wouldn't recommend using this solution if you can avoid it, but it's solved the warnings, at least.
回答6:
####################################### CPP type proving code (identifying type by typeid)
$ cat typeid.cpp
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <time.h>
#include <typeinfo>
#define name(t) printf("%30s : %s\n", #t, typeid(t).name())
// g++|clang++ -o ./typeid.exe typeid.cpp -m32 && ./typeid.exe
// g++|clang++ -o ./typeid.exe typeid.cpp -m64 && ./typeid.exe
int main(int argc, char* argv[]) {
name(ptrdiff_t);
name(intptr_t);
name(uintptr_t);
return 0;
}
####################################### C type proving code (identifying type by _Generic)
$ cat typeid.c
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <time.h>
/* matches the type name of an expression */
#define name_match(e) _Generic((e), \
_Bool: "_Bool", \
char: "char", \
signed char: "signed char", \
unsigned char: "unsigned char", \
short: "short", \
unsigned short: "unsigned short", \
int: "int", \
unsigned int: "unsigned int", \
long: "long", \
unsigned long: "unsigned long", \
long long: "long long", \
unsigned long long: "unsigned long long", \
float: "float", \
double: "double", \
long double: "long double", \
default: "unknown")
#define name(t, e) printf("%30s : %s\n", #t, name_match(e))
int main() {
ptrdiff_t ptrdiff_v = 0;
intptr_t intptr_v = 0;
uintptr_t uintptr_v = 0;
name(ptrdiff_t, ptrdiff_v);
name(intptr_t, intptr_v);
name(uintptr_t, uintptr_v);
}
####################################### run in arch32
$ clang++ -o ./typeid.exe typeid.cpp -m32 && ./typeid.exe
ptrdiff_t : i
intptr_t : i
uintptr_t : j
$ clang -o ./typeid.exe typeid.c -m32 && ./typeid.exe
ptrdiff_t : int
intptr_t : int
uintptr_t : unsigned int
result:
intptr_t == ptrdiff_t
uintptr_t == unsigned ptrdiff_t
####################################### run in arch64
$ clang++ -o ./typeid.exe typeid.cpp -m64 && ./typeid.exe
ptrdiff_t : l
intptr_t : l
uintptr_t : m
$ clang -o ./typeid.exe typeid.c -m64 && ./typeid.exe
ptrdiff_t : long
intptr_t : long
uintptr_t : unsigned long
result:
intptr_t == ptrdiff_t
uintptr_t == unsigned ptrdiff_t
####################################### man 3 printf
t -- A following integer conversion corresponds to a ptrdiff_t argument.
####################################### conclusion
// intptr_t == ptrdiff_t
// uintptr_t == unsigned ptrdiff_t
// so:
// 1) intptr_t has string format %td
// 2) uintptr_t has string format %tu
#include <stdio.h>
#include <stdint.h>
int main(int argc, char *argv[]) {
intptr_t x = 0;
uintptr_t y = 0;
scanf("%td %tu", &x, &y);
printf("out: %td %tu\n", x, y);
return 0;
}