为什么/何时使用`intptr_t`在C中进行types转换?
我有一个关于使用intptr_t
与long int
。 我发现增加内存地址(例如通过手动指针算术)因数据types而异。 例如增加一个字符指针增加1的内存地址,而增加一个int指针增加4,8为双,16为长双等…
起初,我做了这样的事情:
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给我警告我的types转换:“从指针转换为不同大小的整数”。
经过一些谷歌search和结果(后者是一个字吗?),我看到一些人推荐使用intptr_t
:
#include <stdint.h>
…
printf( "pChar: %ld\n", ( intptr_t )pChar ); printf( "pFloat: %ld\n", ( intptr_t )pFloat );
这确实解决了错误。 所以,我想,从现在开始,我应该使用intptr_t
来进行types转换指针…但是后来发现我可以通过用int
replaceint
来解决问题:
printf( "pChar: %ld\n", ( long int )pChar ); printf( "pFloat: %ld\n", ( long int )pFloat );
所以我的问题是,为什么intptr_t
有用,它应该什么时候使用? 在这种情况下,这似乎是多余的。 很显然, myChar
和myFloat
的内存地址太大,无法放入int
…所以将它们typesmyFloat
long int
解决这个问题。
是否有时内存地址太长,以至于long int
? 现在我想起来了,如果你有大于4GB的内存,那么内存地址可能会超过2 ^ 32 – 1(无符号长整型的最大值…),但是C之前就已经创build了可以想象的吧? 还是他们有先见之明?
谢谢!
这是事情:在一些平台上, int
是正确的大小,但在其他平台上, long
是正确的大小。 你怎么知道你应该使用哪一个? 你没有。 有人可能是对的,但标准不能保证它会是哪一个(如果是的话)。 所以标准提供了一个被定义为正确大小的types,不pipe你在哪个平台上。 之前你必须写:
#ifdef PLATFORM_A typedef long intptr; #else typedef int intptr; #endif
现在你只写:
#include <stdint.h>
它涵盖了更多的情况。 想象一下专门为您的代码运行的每个平台上面的代码片段。
intptr_t
是一个新的发明,创造了64位甚至128位内存地址后想象。
如果您需要将指针转换为整数types,则始终使用intptr_t
。 做任何事情都会给将来需要移植代码的人带来不必要的问题。
在Mozilla / Firefox这样的程序中,当人们想要在64位Linux上进行编译时,需要很长时间才能解决所有这些问题。
首先, intptr_t
仅用于数据指针(不是函数),并不保证存在。
那么,不,你不应该用它来打印的目的。 %p
是为了这个。 你只需要把你的指针指向(void*)
然后就可以了。
算术/访问单个字节也是不好的。 转换为(unsigned char*)
。
intptr_t
是真正的罕见场合,你必须将指针解释为整数(它们实际上不是)。 不,如果你不这样做。
你可以通过使用p
转换说明符让你的生活更轻松:
printf("%p\n", (void *)foo);
另外,打印type (u)intptr_t
variables的可移植方法是使用inttypes.h
的PRI*PTR
macros; 以下相当于在我的平台(32位)上使用p
:
printf("%08" PRIxPTR "\n", (uintptr_t)(void *)foo);
为了完全的可移植性,对void *
进行强制转换是必要的,但是在具有统一指针表示的平台上可以省略。