intptr_t和uintptr_t的字符串格式
intptr_t
和uintptr_t
的字符串格式是什么,它对32位和64位架构都有效。
编辑
warning: format '%x' expects type 'unsigned int', but argument 2 has type "AAA"
这是我在64位但不是32位的警告。
intptr_t AAA
这将是来自inttypes.h
的以下宏:
对于printf
: PRIdPTR PRIiPTR PRIoPTR PRIuPTR PRIxPTR PRIXPTR
对于scanf
: SCNdPTR SCNiPTR SCNoPTR SCNuPTR SCNxPTR
用法示例:
uinptr_t p = SOME_VALUE; printf("Here's a pointer for you: %" PRIxPTR "\n", p);
我认为即使long int
也是不安全的,你应该尝试long long int
,它必须存在,因为你正在使用64位架构并且你已经有了intptr_t
。
在某些64位体系结构上(我认为Microsoft Windows会这样), long int
可以保持32位宽度,以满足MS-DOS时代的假设,即short int
总是16位而long int
总是32位。
即使在那些具有32位long int
平台上, printf("%llx", (unsigned long long)AAA);
会工作。 你应该考虑更优选的formsprintf("%jx", (uintmax_t)AAA);
如果可能的话。
请注意,对于某些旧的编译器,您可能需要对64位整数使用"%Lx"
(对于GNU C,使用强制转换为unsigned long long
)或"%I64x"
(对于Visual C ++,使用强制转换为__uint64
)。
在这种情况下,PS %p
可能不好,因为%p
可能在hex之前打印裸字0x
和/或可能打印零填充值。 如果两者都被应用,例如,代码printf("%p\n", (void*)16);
将在32位平台上打印0x00000010
,在64位平台上打印0x00000010
; 海报应该希望只打印10
张。
我认为你应该考虑使用’z’修饰符。 这将转换对应于size_t og ssize_t的任何内容,并且我发现它也适用于(u)intptr_t。
例如:
intptr_t ip = …; printf(“ip =%zd \ n”,ip);
%p
应该作为%x
的替代,因为uintptr_t
被定义为无符号整数,其大小与平台上的指针相同。
编辑:不幸的是,至少在我的编译器上你必须将变量强制转换为(void *)。 但是,我认为将uintptr_t转换为指针是安全的。
我在一个环境中编译了一些代码,这个环境由于某种原因没有在inttypes.h
定义的PRI.PTR
宏,并且其中intptr_t
在32位中定义为int
,在64位中定义为long int
。
我通过使用%li
格式说明符并将变量转换为printf
参数中的long int
来破解警告。 这在这种环境中是安全的,因为intptr_t
永远不会长于long int
,如上所述。
如果你可以避免使用这个解决方案,我不会建议使用这个解决方案,但它至少解决了警告问题。
####################################### CPP type proving code (identifying type by typeid) $ cat typeid.cpp #include #include #include #include #include #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 #include #include #include /* 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 #include 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; }