博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

intptr_t sizeof(int) sizeof(int*) 数据跨平台

Posted on 2016-02-01 16:21  bw_0927  阅读(580)  评论(0)    收藏  举报

http://blog.csdn.net/cs_zhanyb/article/details/16973379

http://blog.csdn.net/justlinux2010/article/details/7490420

http://blog.nklike.com/integer-in-nginx.html   道出了真相

 

最近开始研读Nginx的源代码,首先就遇到如下的代码:

 

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. typedef  intptr_t      ngx_int_t;  
  2. typedef  uintptr_t    ngx_uint_t;  

intptr_t和uintptr_t是什么类型?以前没见过,于是查了一下。

 

这两个数据类型是ISO C99定义的,具体代码在linux平台的/usr/include/stdint.h头文件中。

该头文件中定义intptr_t和uintptr_t这两个数据类型的代码片段如下:

 

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. /* Types for `void *' pointers.  */  
  2. #if __WORDSIZE == 64  
  3. # ifndef __intptr_t_defined  
  4. typedef long int        intptr_t;  
  5. #  define __intptr_t_defined  
  6. # endif  
  7. typedef unsigned long int   uintptr_t;  
  8. #else  
  9. # ifndef __intptr_t_defined  
  10. typedef int         intptr_t;  
  11. #  define __intptr_t_defined  
  12. # endif  
  13. typedef unsigned int        uintptr_t;  
  14. #endif  

在64位的机器上,intptr_t和uintptr_t分别是long int、unsigned long int的别名;在32位的机器上,intptr_t和uintptr_t分别是int、unsigned int的别名。

那么为什么要用typedef定义新的别名呢?我想主要是为了提高程序的可移植性(在32位和64位的机器上)。很明显,上述代码会根据宿主机器的位数为intptr_t和uintptr_t适配相应的数据类型。

另外,如注释所言,定义这两个数据类型别名也是为了“void *”指针。

 

在C语言中,任何类型的指针都可以转换为void *类型,并且在将它转换回原来的类型时不会丢失信息。

==================================

很明显intptr_t不是指针类型,但是上边的一句注释(/* Types for `void *' pointers. */)让人很疑惑。既然不是指针类型,但是为什么说类型是为了“void *”指针?

 

又查了一下在《深入分析Linux内核源码》中找到了答案,原文描述如下

 

尽管在混合不同数据类型时你必须小心, 有时有很好的理由这样做. 一种情况是因为内存存取, 与内核相关时是特殊的. 概念上, 尽管地址是指针, 内存管理常常使用一个无符号的整数类型更好地完成; 内核对待物理内存如同一个大数组, 并且内存地址只是一个数组索引. 进一步地, 一个指针容易解引用; 当直接处理内存存取时, 你几乎从不想以这种方式解引用. 使用一个整数类型避免了这种解引用, 因此避免了 bug. 因此, 内核中通常的内存地址常常是 unsigned long, 利用了指针和长整型一直是相同大小的这个事实, 至少在 Linux 目前支持的所有平台上.

因为其所值的原因, C99 标准定义了 intptr_t 和 uintptr_t 类型给一个可以持有一个指针值的整型变量. 但是, 这些类型几乎没在 2.6 内核中使用。

 

=============

可以看到注释是: Types for `void *’ pointers. 那么这是什么含义呢?

我们知道所谓的指针,其实是内存的地址,而内容是该地址内存中实际存储的数据。void *是指无类型指针,当需要进行转化时,这个类型可以被安全的在 void * 和整数间转换,而不会出现由于指针和整型的字宽不同导致的问题。

C语言中,指针和整数之间的转换经常用到(多用于需要精确控制数据在内存中的精确布局时),在32位平台上,由于指针类型的字宽和int相同,所以我们不太在意这个问题。但是到了 64 位平台上,由于目前几乎所有64位系统都采用LP64模型,既整数依旧是32位,而指针是64位的。intptr_t 这个数据类型就成了安全跨平台编程的保证。也就是说,当你需要把指针作为一个整数来运算时,转换成 intptr_t才是安全的,可以在运算完毕安全的转回指针类型。

 

在64位机器上:

cout << "sizeof void*" << sizeof(void*) << endl;
cout << "sizeof int " << sizeof(int) << endl;
cout << "sizeof long int " << sizeof(long int) << endl;
cout << "sizeof int*" << sizeof(int*) << endl;

 

结果:

sizeof void*: 8
sizeof int: 4
sizeof long int: 8
sizeof int*: 8

 

 

http://blog.csdn.net/luotuo44/article/details/38780157

ntptr_t是一个很重要的类型,特别是在64位系统中。如果你要对两个指针进行运算,最好是先将这两个指针转换成intptr_t类型,然后才进行运算。因为在一些64位系统中,int还是32位,而指针类型为64位,所以两个指针相减,其结果对于32位的int来说,可能会溢出。