为什么/何时使用`intptr_t`在C中进行类型转换?

gri*_*tis 43 c types memory-management casting intptr

我有一个关于使用intptr_tvs. 的问题long int.我观察到递增内存地址(例如通过手动指针算术)因数据类型而异.例如,递增char指针会将1添加到内存地址,而递增int指针会为double添加4,8,为long double添加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 );
Run Code Online (Sandbox Code Playgroud)

编译和执行得很好,但XCode给了我警告我的类型转换:"从指针转换为不同大小的整数."

经过一些谷歌搜索和binging(后者还是一个词?),我看到有些人推荐使用intptr_t:

#include <stdint.h>
Run Code Online (Sandbox Code Playgroud)

...

printf( "pChar:  %ld\n", ( intptr_t )pChar );
printf( "pFloat: %ld\n", ( intptr_t )pFloat );
Run Code Online (Sandbox Code Playgroud)

这确实解决了错误.所以,我想,从现在开始,我应该使用intptr_t类型转换指针...但是经过一些烦躁之后,我发现我可以通过替换intlong int:

printf( "pChar:  %ld\n", ( long int )pChar );
printf( "pFloat: %ld\n", ( long int )pFloat );
Run Code Online (Sandbox Code Playgroud)

所以我的问题是,为什么intptr_t有用,什么时候应该使用?在这种情况下,这似乎是多余的.显然,对于内存地址myCharmyFloat只是太大,不适合在int...所以他们类型转换到long int解决了问题的问题.

有时候内存地址太大了long int吗?现在我考虑一下,我想如果你有超过4GB的内存,那么内存地址可能会超过2 ^ 32 - 1(无符号长整数的最大值......),但是在此之前很久就创建了C可以想象,对吧?还是他们有先见之明?

谢谢!

Zan*_*ynx 45

intptr_t 是一个新的发明,是在想象出64位甚至128位内存地址之后创建的.

如果你曾经需要将指针到一个整数类型,总是使用intptr_t.对于需要在将来移植代码的人来说,做其他事情会带来不必要的问题.

当人们想在64位Linux上编译它时,花了很长时间才能解决Mozilla/Firefox等程序中的所有错误.

  • 最好使用`uintptr_t`.签名类型很乱,指针肯定没有意义...... (13认同)
  • 没关系,最后一点是一个愚蠢的问题.:) (2认同)
  • @MestreLion 这不是真的,它在 C99 中是可选的 (2认同)

Chr*_*utz 36

事情就是这样:在某些平台上,int尺寸合适,但在其他平台上尺寸long合适.你怎么知道哪一个是你应该使用的?你没有.一个可能是正确的,但标准不保证它将是哪一个(如果它是).因此,无论您使用什么平台,标准都会提供一个定义为正确大小的类型.之前你必须写的地方:

#ifdef PLATFORM_A
  typedef long intptr;
#else
  typedef int intptr;
#endif
Run Code Online (Sandbox Code Playgroud)

现在你只需写:

#include <stdint.h>
Run Code Online (Sandbox Code Playgroud)

它涵盖了更多的案例.想象一下,为您的代码运行的每个平台专门化上面的代码片段.

  • @caravaggisto - 不。“long”仅保证为 32 位,可能无法在 64 位平台上工作。您始终可以使用“long long”,但这在 C99 之前不存在。我怀疑分配是否重要。这更多的是正确性的问题。 (3认同)
  • 我对任何教你在指针和整数之间进行转换的 C 书籍都非常怀疑。事实上,几乎所有的强制转换都表明存在错误;它们至少是一种代码味道。指针/整数转换要糟糕得多。 (2认同)
  • @ZanLynx WinAPI是一个糟糕的API,专为80年代中期严重破坏的标准C编译器而设计。自Win16时代以来,它并没有太大变化。MS试图杀死它是有原因的。 (2认同)

Jen*_*edt 10

首先,intptr_t仅用于数据指针(不是函数),并且不保证存在.

然后,不,你不应该用它来打印.该%p是这一点.你只需要把指针扔到(void*)那里就可以了.

算术/访问单个字节也没有用.(unsigned char*)转而转向.

intptr_t在极少数情况下,您必须将指针解释为整数(实际上它们并非如此).如果你不能,那就不要这样做.

  • @caravaggisto,这在很大程度上取决于架构.一些架构具有分段存储器,因此地址由两部分组成.只是简单的整数加法可能不会总是给你一个有效的地址.如果你分配了一个足够大的块,那么`unsigned char`的算法就可以了. (3认同)

Chr*_*oph 10

您可以使用p转换说明符让您的生活更轻松:

printf("%p\n", (void *)foo);
Run Code Online (Sandbox Code Playgroud)

另外,打印变量类型的便携方式(u)intptr_t是使用PRI*PTR来自的宏inttypes.h; 以下相当于p在我的平台上使用(32位):

printf("%08" PRIxPTR "\n", (uintptr_t)(void *)foo);
Run Code Online (Sandbox Code Playgroud)

转换void *为完全可移植性所必需的,但在具有统一指针表示的平台上可以省略.