小谈C语言中常见数据类型在32及64位机上的使用(zz)

关键字: c语言,数据类型,32位,64位

1、概述

  C语言有一些非常基本的数据类型,正是这些基本类型让我们可以延伸了无限的用户自定义类型,本文主要介绍了 int, size_t, time_t, long, long long int 等基本数据类型在Linux32 及 Linux64 的使用情况。表面看上去,这些类型确实太基础太简单,似乎没啥可讲的,实事似乎也是如此,用过C的对这些都已经非常熟悉了,这还用讲?在PC 64位机器 出来之前,我们确实不用太关注这些,因为在32位机上编程,似乎很少出现过什么问题,但64位机出来了,象Linux 也支持64位机器,问题就来了,为什么?因为它们的长度发生了变化,而我们的程序也就有可能需要改变一下。

2、举例

先举个例子,如下:

 

C代码
  1. #include <stdio.h> 
  2. #include <stdlib.h> 
  3.  
  4. staticvoid get_length(size_t *size) 
  5.     if (size) 
  6.         *size = 100; 
  7.  
  8. staticvoid test(void
  9.     char *buf = strdup("hello world"); 
  10.     int  n; 
  11.  
  12.     printf("buf: %s\n", buf); 
  13.     get_length((size_t*) &n); 
  14.  
  15.     printf("buf: %s, n: %d\n",  buf, n); 
  16.     free(buf); 
  17.  
  18. int main(int argc, char *argv[]) 
  19.     test(); 
  20.     return (0); 
#include <stdio.h>  #include <stdlib.h>    static void get_length(size_t *size)  {      if (size)          *size = 100;  }    static void test(void)  {      char *buf = strdup("hello world");      int  n;        printf("buf: %s\n", buf);      get_length((size_t*) &n);        printf("buf: %s, n: %d\n",  buf, n);      free(buf);  }    int main(int argc, char *argv[])  {      test();      return (0);  }

 

  首先将此程序在32位机的 Linux 上运行一下,如下:

buf: hello world

buf: hello world, n: 100

OK,如我们所料,一切正常。

 

  然后再将些程序在64位机的 Linux 上运行一下,如下:

buf: hello world

buf: (null), n: 100

  奇怪的现象出来了,怎么printf出的结果为空呢?晕菜,为啥经过 get_length()/1 后世界改变了,buf 的内容没有了,被指向一个空指针,而 buf 明明是还没有被释放呀。赶快用 valgrind 检查一下,

valgrind --tool=memcheck --leak-check=yes --show-reachable=yes ./a.out

“2 bytes in 1 blocks are definitely lost in loss record 1 of 1”,说有块内存未被释放,而在 test() 后面确实释放过 buf 呀,谁偷偷地给释放了而没有告诉俺?更晕菜,难道是 libc 的问题?再用 valgrind 在32位机检查一下,一切OK,没有出现64位机上的错误提示,说明内存确实由 test() 中的 free(buf) 释放了。

  正当对此问题百思不解时,忽然想到一个问题 int * 至 size_t*  类型转换会不会有问题?因为 size_t 在32位机上是4字节,而在64位机上是8字节,int在32位及64位机上都是4字节,嗯,问题就在于此,再回头仔细看看上述代码,在 test() 中将 &n 由 int * 强制转换成 size_t *, 这样可以避免编译警告,但在 get_length()/1 中呢?它是不会知道 size_t *size 中 size 所指空间是4字节的,而依然当8字节对待,这样在对 *size = 100 进行赋值时就发生了改变,size 所指的8字节空间发生改变,而实际应该只改变4字节才是,这便是问题的关键所在,所以在遇到此类问题时,一定得要注意基本类型在不同机器上的空间大小了。

 

3、小结

  以上的例子只是一个简单的例子,也许还容易看得出来,当我们的项目比较大时,这种错误可能会偶尔发生一下,那可能就是致命的了,因为有时它并不 会导致程序 异常退出产生core文件,但却会改变我们的运行结果,本人就因此问题调试了两天多的时间才找到原因,另外,即使因此问题产生了 core 文件,你会发现用 gdb 调试该 core 时根本找不到原因所在。

 

下面列出一些基本类型在32位及64位机上的大小差异

  int long size_t time_t long long int
32位机器 4字节 4字节 4字节 4字节 8字节
64位机器 4字节 8字节 8字节 8字节 8字节

 

在写跨平台的程序时,一定要注意这些基本类型的长度大小。

---------------------------------

一、程序运行平台
       不同的平台上对不同数据类型分配的字节数是不同的。
       个人对平台的理解是CPU+OS+Compiler,是因为:
       1、64位机器也可以装32位系统(x64装XP);
       2、32位机器上可以有16/32位的编译器(XP上有tc是16位的,其他常见的是32位的);
       3、即使是32位的编译器也可以弄出64位的integer来(int64)。
       以上这些是基于常见的wintel平台,加上我们可能很少机会接触的其它平台(其它的CPU和OS),所以个人认为所谓平台的概念是三者的组合。
       虽然三者的长度可以不一样,但显然相互配合(即长度相等,32位的CPU+32位的OS+32位的Compiler)发挥的能量最大。
       理论上来讲 我觉得数据类型的字节数应该是由CPU决定的,但是实际上主要由编译器决定(占多少位由编译器在编译期间说了算)。

二、常用数据类型对应字节数
       可用如sizeof(char),sizeof(char*)等得出

       32位编译器:

       char :1个字节
       char*(即指针变量): 4个字节(32位的寻址空间是2^32, 即32个bit,也就是4个字节。同理64位编译器)
       short int : 2个字节
       int: 4个字节
       unsigned int : 4个字节
       float: 4个字节
       double: 8个字节
       long: 4个字节
       long long: 8个字节
       unsigned long: 4个字节

       64位编译器:

       char :1个字节
       char*(即指针变量): 8个字节
       short int : 2个字节
       int: 4个字节
       unsigned int : 4个字节
       float: 4个字节
       double: 8个字节
       long: 8个字节
       long long: 8个字节
       unsigned long: 8个字节

posted @ 2013-03-06 00:32  功夫 熊猫  阅读(913)  评论(0编辑  收藏  举报