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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6326338/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 08:54:31  来源:igfitidea点击:

Why / when to use `intptr_t` for type-casting in C?

cmemory-managementtypescastingintptr

提问by grisaitis

I have a question regarding using intptr_tvs. long int. I've observed that incrementing memory addresses (e.g. via manual pointer arithmetic) differs by data type. For instance incrementing a char pointer adds 1 to the memory address, whereas incrementing an int pointer adds 4, 8 for a double, 16 for a long double, etc...

我有一个关于使用intptr_tvs.的问题long int。我观察到递增内存地址(例如,通过手动指针算术)因数据类型而异。例如,增加 char 指针会将内存地址加 1,而增加 int 指针会为 double 增加 4、8,为 long double 增加 16,等等......

At first I did something like this:

起初我做了这样的事情:

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 );

which compiled and executed just fine, but XCode gave me warnings for my typecasting: "Cast from pointer to integer of different size."

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

After some googling and binging (is the latter a word yet?), I saw some people recommend using intptr_t:

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

#include <stdint.h>

...

...

printf( "pChar:  %ld\n", ( intptr_t )pChar );
printf( "pFloat: %ld\n", ( intptr_t )pFloat );

which indeed resolves the errors. So, I thought, from now on, I should use intptr_tfor typecasting pointers... But then after some fidgeting, I found that I could solve the problem by just replacing intwith long int:

这确实解决了错误。所以,我想,从现在开始,我应该intptr_t用于类型转换指针......但是经过一番烦躁之后,我发现我可以通过替换int为来解决问题long int

printf( "pChar:  %ld\n", ( long int )pChar );
printf( "pFloat: %ld\n", ( long int )pFloat );

So my question is, why is intptr_tuseful, and when should it used? It seems superfluous in this instance. Clearly, the memory addresses for myCharand myFloatwere just too big to fit in an int... so typecasting them to long ints solved the problem.

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

Is it that sometimes memory addresses are too big for long intas well? Now that I think about it, I guess that's possible if you have > 4GB of RAM, in which case memory addresses could exceed 2^32 - 1 (max value for unsigned long ints...) but C was created long before that was imaginable, right? Or were they that prescient?

是不是有时内存地址也太大了long int?现在我考虑了一下,我想如果你有 > 4GB 的 RAM,这是可能的,在这种情况下,内存地址可能超过 2^32 - 1(无符号长整数的最大值......)但是 C 早在此之前就被创建了可以想象,对吧?还是他们有先见之明?

Thanks!

谢谢!

采纳答案by Chris Lutz

Here's the thing: on some platforms, intis the right size, but on others, longis the right size. How do you know which one is the one you should use? You don't. One might be right, but the standard makes no guarantees about which one it would be (if it is either). So the standard provides a type that is defined to be the correct size, regardless of what platform you're on. Where before you had to write:

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

#ifdef PLATFORM_A
  typedef long intptr;
#else
  typedef int intptr;
#endif

Now you just write:

现在你只需写:

#include <stdint.h>

And it covers so many more cases. Imagine specializing the snippet above for every single platformyour code runs on.

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

回答by Zan Lynx

intptr_tis a new invention, created after 64-bit and even 128-bit memory addresses were imagined.

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

If you everneed to cast a pointer into an integer type, alwaysuse intptr_t. Doing anything else will cause unnecessary problems for people who need to port your code in the future.

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

It took a long time to iron out all of the bugs with this in programs like Mozilla/Firefox when people wanted to compile it on 64-bit Linux.

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

回答by Jens Gustedt

First, intptr_tis only for data pointers (not functions) and is not guaranteed to exist.

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

Then, no, you shouldn't use it for the purpose of printing. The %pis for that. You just have to cast your pointer to (void*)and there you go.

那么,不,您不应该将它用于打印目的。该%p是这一点。你只需要把你的指针投射到(void*)那里就可以了。

It is also no good for arithmetic / accessing individual bytes. Cast to (unsigned char*)instead.

它也不适用于算术/访问单个字节。转为(unsigned char*)改为。

intptr_tis really for the rare occasions that you have to interpret pointers as integers (which they really aren't). Don't that if you mustn't.

intptr_t真的是在极少数情况下,您必须将指针解释为整数(实际上并非如此)。如果你必须不要那样做。

回答by Christoph

You could make your life easier by using the pconversion specifier:

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

printf("%p\n", (void *)foo);

Also, the portable way to print a variable of type (u)intptr_tis to use the PRI*PTRmacros from inttypes.h; the following is equivalent to using pon my platform (32-bit):

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

printf("%08" PRIxPTR "\n", (uintptr_t)(void *)foo);

The casts to void *are necessary for full portability, but can be omitted on platforms with uniform pointer representations.

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