参见 http://en.cppreference.com/w/cpp/types/size_t

  size_t其实与uintptr_t一个道理。就是一个东西。指针其实就是寻址,与地址总线位数一致,编译器根据平台决定,从性能和可移植性分析有其由来。

  之前在《内存拷贝的注意事项》一文中提到过size_t,可能许多人对这个类型不太熟悉没有用过或者根本不敢去用,最近看到一篇文章对这个类型讲的比较详细,便翻译过来让不熟悉的同学可以知道它产生的原因以及如何使用。
  原文地址: Why size_t matters


  前言:使用size_t可能会提高代码的可移植性、有效性或者可读性,或许同时提高这三者。

  在标准C库中的许多函数使用的参数或者返回值都是表示的用字节表示的对象大小,比如说malloc(n) 函数的参数n指明了需要申请的空间大小,还有memcpy(s1, s2, n)的最后一个参数,表明需要复制的内存大小,strlen(s)函数的返回值表明了以'\0'结尾的字符串的长度(不包括'\0'),其返回值并不是该字符串的实际长度,因为要去掉'\0'。
  或许你会认为这些参数或者返回值应该被申明为int类型(或者long或者unsigned),但是事实上并不是。C标准中将他们定义为size_t。标准中记载malloc的申明应该出现在,定义为:

void *malloc(size_t n);

  memcpy和strlen的申明应该出现在中:

void *memcpy(void *s1, void const *s2, size_t n);
size_t strlen(char const *s);

  size_t还经常出现在C++标准库中,此外,C++库中经常会使用一个相似的类型size_type,用的可能比size_t还要多。
  据我所知,大部分的C和C++程序员害怕这些库使用size_t,因为他们不知道size_t代表什么或者为什么这些库需要使用它,归根结底,原因在于他们什么时候什么地方需要用到它。

可移植性问题

  早期的C语言(由Brian Kernighan 和 Dennis Ritchie 在The C Programming Language书中所写,Prentice-Hall, 1978)并没有提供size_t类型,C标准委员会为了解决移植性问题将size_t引入,举例如下:
  让我们来写一个可移植的标准memcpy函数,我们将会看到一些不同的申明和它们在不同平台不同大小的地址空间上编译下的情况。
  回忆memcpy(s1, s2, n)函数,它将s2指向地址开始的n个字节拷贝到s2指向的地址,返回s1,这个函数可以拷贝任何数据类型,所以参数和返回值的类型应该为可以指向任何类型的void*,同时,源地址不应该被改变,所以第二个参数s2类型应该为const void*,这些都不是问题。
  真正的问题在于我们如何申明第三个参数,它代表了源对象的大小,我相信大部分程序员都会选择int:

void *memcpy(void *s1, void const *s2, int n);

  使用int类型在大部分情况下都是可以的,但是并不是所有情况下都可以。int是有符号的,它可以表示负数,但是,大小不可能是复数。所以我们可以使用unsigned int代替它让第三个参数表示的范围更大。
  在大部分机器上,unsigned int的最大值要比int的最大值大两倍,比如说再也给16位的机器上,unsigned int的最大值为65535,int的最大值为32767。
  尽管int类型的大小依赖于C编译器的实现,但是在给定的平台上int对象的大小和unsigned int对象的大小是一样的。因此,使用unsigned int修饰第三个参数的代价与int是相同的:

void *memcpy(void *s1, void const *s2, unsigned int n);  

  这样似乎没有问题了,unsigned int可以表示最大类型的对象大小了,这种情况只有在整形和指针类型具有相同大小的情况下,比如说在IP16中,整形和指针都占2个字节(16位),而在IP32上面,整形和指针都占4个字节(32位)。(参见下面C数据模型表示法)

C数据模型表示法
  最近,我偶然发现几篇文章,他们使用简明的标记来表述不同目标平台下c语言数据的实现。我还没有找到这个标记的来源,正式的语法,甚至连名字都没有,但他似乎很简单,即使没有正规的定义也可以很容易使用起来。这些标记的一边形式形如:
  I nI L nL LL nLL P nP。
  其中每个大写字母(或成对出现)代表一个C的数据类型,每一个对应的n是这个类型包含的位数。I代表int,L代表long,LL代表long long,以及P代表指针(指向数据,而不是函数)。每个字母和数字都是可选的。
  例如,I16P32架构支持16位int和32位指针类型,没有指明是否支持long或者long long。如果两个连续的类型具有相同的大小,通常省略第一个数字。例如,你可以将I16L32P32写为I16LP32,这是一个支持16位int,32位long,和32位指针的架构。
  标记通常把字母分类在一起,所以可以按照其对应的数字升序排列。例如,IL32LL64P32表示支持32位int,32位long,64位long long和32位指针的架构;然而,通常写作ILP32LL64。

  不幸的是,这种memcpy的申明在I16LP32架构上(整形是16-bit 长整形和指针类型时32-bits)显得不够用了,比如说摩托罗拉第一代处理器68000,在这种情况下,处理器可能拷贝的数据大于65535个字节,但是这个函数第三个参数n不能处理这么大的数据。
  什么?你说很容易就可以改正?只需要把memcpy的第三个参数的类型修改一下:

void *memcpy(void *s1, void const *s2, unsigned long  n); 

  你可以在I16LP32目标架构上使用这个函数了,它可以处理更大的数据。而且在IP16和IP32平台上效果也还行,说明它确实给出了memcpy的一种移植性较好的申明。但是,在IP16平台上相比于使用unsigned int,你使用unsigned long可能会使你的代码运行效率大打折扣(代码量变大而且运行变慢)。
  在标准C中规定,长整形(无论无符号或者有符号)至少占用32位,因此在IP16平台上支持标准C的话,那么它一定是IP16L32 平台。这些平台通常使用一对16位的字来实现32位的长整形。在这种情况下,移动一个长整形需要两条机器指令,每条移动一个16位的块。事实上,这个平台上的大部分的32位操作都需要至上两条指令。
  因此,以可移植性为名将memcpy的第三个参数申明为unsigned long而降低某些平台的性能是我们所不希望看到的。使用size_t可以有效避免这种情况。
  size_t类型是一个类型定义,通常将一些无符号的整形定义为size_t,比如说unsigned int或者unsigned long,甚至unsigned long long。每一个标准C实现应该选择足够大的无符号整形来代表该平台上最大可能出现的对象大小。

使用size_t

  size_t的定义在<stddef.h>, <stdio.h>, <stdlib.h>, <string.h>, <time.h>和<wchar.h>这些标准C头文件中,也出现在相应的C++头文件, 等等中,你应该在你的头文件中至少包含一个这样的头文件在使用size_t之前。
  包含以上任何C头文件(由C或C++编译的程序)表明将size_t作为全局关键字。包含以上任何C++头文件(当你只能在C++中做某种操作时)表明将size_t作为std命名空间的成员。   根据定义,size_t是sizeof关键字(注:sizeof是关键字,并非运算符)运算结果的类型。所以,应当通过适当的方式声明n来完成赋值:

n = sizeof(thing);

  考虑到可移植性和程序效率,n应该被申明为size_t类型。类似的,下面的foo函数的参数也应当被申明为sizeof:

foo(sizeof(thing));

  参数中带有size_t的函数通常会含有局部变量用来对数组的大小或者索引进行计算,在这种情况下,size_t是个不错的选择。
  适当地使用size_t还会使你的代码变得如同自带文档。当你看到一个对象声明为size_t类型,你马上就知道它代表字节大小或数组索引,而不是错误代码或者是一个普通的算术值。
  在我接下来的一些文章的例子中会使用size_t,敬请期待!

为什么size_t重要?的更多相关文章

  1. size_t和size_type

    size_t和size_type是为了独立于及其而定义的类型,因为比如在一台电脑上int为2b,而另一台电脑上是4b,这样就给程序的可移植性带来了麻烦.为了解决这个问题,在库内定义了如上类型,其实si ...

  2. size_t 类型

    1 关于size_t定义 size_t是一种数据相关的无符号类型,它被设计得足够大以便能够内存中任意对象的大小.在cstddef头文件中定义了size_t类型,这个文件是C标准库stddef.h头文件 ...

  3. size_t 和 size_type的区别

    为了使自己的程序有很好的移植性,c++程序员应该尽量使用size_t和size_type而不是int, unsigned 1. size_t是全局定义的类型:size_type是STL类中定义的类型属 ...

  4. size_t总结

    1.sizeof返回的必定是无符号整形,在标准c中通过 typedef 将返回值类型定义为size_t. 若用printf输出size_t类型时,C99中定义格式符%zd;若编译器不支持可以尝试%u或 ...

  5. v.size() return size_t not int 返回无符号整型数

    In the C++ STL, the vector size() function return size_t, which is unsigned int, not int. So imagine ...

  6. size_t 与 int 区别

    size_t是无符号的,并且是平台无关的,表示0-MAXINT的范围, 但是如果传入的是负数,会被编译成他的补码. size_t是标准规定的一个同义词,它的原始定义放在stddef.h里面,不同的环境 ...

  7. size_type、size_t、differentce_type以及ptrdiff_t

      目录(?)[-] size_type size_t different_type ptrdiff_t size_t是unsigned类型,用于指明数组长度或下标,它必须是一个正数,std::siz ...

  8. Unix编程之size_t、ssize_t

    http://blog.csdn.net/lalor/article/details/7426184 首先,我非常肯定以 及确定的告诉你ssize_t是有符号整型,在32位机器上等同与int,在64位 ...

  9. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

    #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)宏的运行机理:1. ( (TYPE *)0 ) 将零转型为TY ...

  10. size_t和ssize_t

    Ssize_t 与size_t 跟踪linux源码得到以下宏: #ifndef _SIZE_T #define _SIZE_T typedef __kernel_size_t         size ...

随机推荐

  1. std::u32string conversion to/from std::string and std::u16string

    I need to convert between UTF-8, UTF-16 and UTF-32 for different API's/modules and since I know have ...

  2. hihoCoder挑战赛28 题目1 : 异或排序

    题目1 : 异或排序 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个长度为 n 的非负整数序列 a[1..n] 你需要求有多少个非负整数 S 满足以下两个条件: ...

  3. Ubuntu 16.04系统下软件中心Software闪退解决办法

    按住Ctrl+Alt+T打开终端输入: sudo apt-get update //更新 sudo apt-get dist-upgrade //升级 sudo apt-get install --r ...

  4. MUI---IOS切换到后台继续播放音乐

    应用切换到后台继续音乐播放HBuilder默认生成的应用在iOS是不支持后台音乐播放的,当应用切换到后台时音乐将暂停播放,下次切换到前台继续播放.如果要支持应用切换到后台后继续播放音乐功能需要进行额外 ...

  5. yii---load怎么使用

    在用YII进行二次开发的时候,看到登录方法有一个load的方法: public function actionLogin() { if (Yii::$app->request->isPos ...

  6. hdu6393Traffic Network in Numazu【树状数组】【LCA】

    Traffic Network in Numazu Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (J ...

  7. Python实现KNN算法及手写程序识别

    1.Python实现KNN算法 输入:inX:与现有数据集(1xN)进行比较的向量   dataSet:已知向量的大小m数据集(NxM)   个标签:数据集标签(1xM矢量)   k:用于比较的邻居数 ...

  8. Python数据分析必备Anaconda安装、快捷键、包安装

    Python数据分析必备: 1.Anaconda操作 Anaconda是一个用于科学计算的Python发行版,支持 Linux, Mac, Windows系统,提供了包管理与环境管理的功能,可以很方便 ...

  9. 【转】Ant与Ivy的安装

    一.简介 Apache Ant,是一个将软件编译.测试.部署等步骤联系在一起加以自动化的一个工具,大多用于Java环境中的软件开发.更多介绍 Apache Ivy,是一个管理项目依赖的工具.更多介绍请 ...

  10. hihocoder 1320 - 压缩字符串 - [hiho一下160周]

    这道题目可以说是一道非常好非常一颗赛艇的DP题了. 需要注意的是,其中情形3),字符串必然能完全转化为 N(str)形式,如果有N(str1)M(str2)等等另外样式,应该首先使用拼接形式对其进行划 ...