我有一个关于使用intptr_t
与long int
的问题。我观察到增量存储器地址(例如通过手动指针算术)因数据类型而异。例如,递增一个char指针会将1添加到内存地址,而递增一个int指针会增加4,8为double,16为long double等等...
起初我做了类似的事情:
char myChar, *pChar;
float myFloat, *pFloat;
pChar = &myChar;
pFloat = &myFloat;
printf( "pChar: %d\n", ( int )pChar );
printf( "pFloat: %d\n", ( int )pFloat );
pChar++;
pFloat++;
printf( "and then after incrementing,:\n\n" );
printf( "pChar: %d\n", (int)pChar );
printf( "pFloat: %d\n", (int)pFloat );
编译并执行得很好,但XCode给了我警告我的类型转换:“从指针转换为不同大小的整数。”
经过一些谷歌搜索和binging(后者还是一个词?),我看到有些人建议使用intptr_t
:
#include <stdint.h>
...
printf( "pChar: %ld\n", ( intptr_t )pChar );
printf( "pFloat: %ld\n", ( intptr_t )pFloat );
确实解决了错误。所以,我想,从现在开始,我应该使用intptr_t
来进行类型转换...但是经过一些烦躁之后,我发现我只需用{{1}替换int
即可解决问题}:
long int
所以我的问题是,为什么printf( "pChar: %ld\n", ( long int )pChar );
printf( "pFloat: %ld\n", ( long int )pFloat );
有用,什么时候应该使用?在这种情况下,这似乎是多余的。显然,intptr_t
和myChar
的内存地址太大而无法放入myFloat
...因此将它们转换为int
来解决问题。
有时候内存地址对于long int
来说太大了吗?现在我考虑一下,如果你有&gt;我想这是可能的。 4GB的RAM,在这种情况下,内存地址可能会超过2 ^ 32 - 1(无符号长整数的最大值......)但C在很久之前就被创建了,对吧?还是他们有先见之明?
谢谢!
答案 0 :(得分:45)
intptr_t
是一项新发明,是在想象出64位甚至128位内存地址后创建的。
如果您 需要将指针转换为整数类型,始终使用intptr_t
。对于需要在将来移植代码的人来说,做其他事情会带来不必要的问题。
当人们想在64位Linux上编译它时,花了很长时间才能解决Mozilla / Firefox等程序中的所有错误。
答案 1 :(得分:36)
事情就是这样:在某些平台上,int
的大小合适,但在其他平台上,long
的大小合适。你怎么知道哪一个是你应该使用的?你没有。一个可能是正确的,但标准不保证它将是哪一个(如果它是)。因此,无论您使用什么平台,标准都会提供一个定义为正确大小的类型。之前你必须写的地方:
#ifdef PLATFORM_A
typedef long intptr;
#else
typedef int intptr;
#endif
现在你写一下:
#include <stdint.h>
它涵盖了更多案例。想象一下,专门针对运行代码的每个平台上面的代码片段。
答案 2 :(得分:10)
首先,intptr_t
仅用于数据指针(不是函数),并且不保证存在。
然后,不,你不应该用它来打印。 %p
就是为了这个。你只需要将指针指向(void*)
然后就可以了。
算术/访问单个字节也没有用。转而使用(unsigned char*)
。
intptr_t
实际上是在极少数情况下你必须将指针解释为整数(它们实际上并非如此)。如果你不能,那就不要这样做。
答案 3 :(得分:9)
使用p
转换说明符可以让您的生活更轻松:
printf("%p\n", (void *)foo);
此外,打印(u)intptr_t
类型变量的便携方式是使用PRI*PTR
中的inttypes.h
个宏;以下等同于在我的平台上使用p
(32位):
printf("%08" PRIxPTR "\n", (uintptr_t)(void *)foo);
void *
的强制转换是完全可移植性所必需的,但在具有统一指针表示的平台上可以省略。