size_t为什么重要


参考:https://www.zhihu.com/question/24773728/answer/66535663

  前言:使用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,敬请期待!

转载于:https://www.cnblogs.com/xiaochouk/p/9310498.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/249941.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

html--form表单常用操作

form表单 用于收集用户信息&#xff0c;如&#xff1a;登录、注册等场景&#xff1b;所有要提交的数据都必须放在form标签中<form action" " method" "> action&#xff1a;提交地址、动作&#xff0c;与input标签中type标签的submit属性相关联。 &…

MySQL触发器(转载)

触发器&#xff08;trigger&#xff09;是数据库中的一个很重要的、很实用的基于事件的处理器&#xff0c;在处理一些业务需求的时候&#xff0c;使用触发器会很方便。似乎在《高性能MySQL》中&#xff0c;对触发器作了一定的描述&#xff0c;也提到使用中的一些优势和局限性&a…

神级bug解决方法

真的是神级bug,util包中的Arrays类导入不了&#xff0c;一直报错。原因&#xff1a;JDK 1.8和Myeclipse 8.5不兼容&#xff0c;导致java.util.Arrays类无法被编译。所以报错。解决方法&#xff1a;1.降低jdk版本。2.升高Myeclipse版本转载于:https://www.cnblogs.com/yanlongw/…

es6注意点

补救方法&#xff1a; 详情&#xff1a;http://es6.ruanyifeng.com/#docs/array 取出文本内容 实现深拷贝 jq实现不完全深拷贝 jQuery.extend jQuery.fn.extend function () {var options, name, src, copy, copyIsArray, clone,target arguments[0] || {},i 1,length ar…

input标签用法解读

HTML5/HTML中标签用法解读 OK&#xff01;今天博主为小伙伴们介绍的内容是HTML5/HTML中标签的用法&#xff0c;&#xff0c;&#xff0c; &#xff0c;emmm图文并茂哦&#xff01; 下面正式开始内容的介绍&#xff1a;首先&#xff0c;直观上说标签规定了用户可以在其中输入数据…

SpringBoot项目遇到的一些问题

SpringBoot项目整合JPA报错转载于:https://www.cnblogs.com/xb1223/p/10195054.html

关于SpringBoot中的多数据源集成

引言 其实对于分库分表这块的场景&#xff0c;目前市场上有很多成熟的开源中间件&#xff0c;eg&#xff1a;MyCAT&#xff0c;Cobar&#xff0c;sharding-JDBC等。 本文主要是介绍基于springboot的多数据源切换&#xff0c;轻量级的一种集成方案&#xff0c;对于小型的应用可…

实现vue2.0响应式的基本思路

注意&#xff0c;这里只是实现思路的还原&#xff0c;对于里面各种细节的实现&#xff0c;比如说数组里面数据的操作的监听&#xff0c;以及对象嵌套这些细节本实例都不会涉及到&#xff0c;如果想了解更加细节的实现&#xff0c;可以通过阅读源码 observer文件夹以及instance文…

HTML标签类型及特点

一、 概述 HTML&#xff08;Hyper Text Markup Language &#xff09;作为一种标记语言&#xff0c;网页所有的内容均书写在标签内部&#xff0c;标签是组成Html页面的基本元素&#xff0c;因此对标签特性的理解在HTML的学习过程中比较重要。 二、基本分类 HTML中的标签从闭…

打开页面

*<a href"javascript:void(0)" title"google" οnclick"window.parent.addTab(, 测试, Admin/UserRole, 100000)">测试444</a>*转载于:https://www.cnblogs.com/niyl/p/10196528.html

python 大量使用json 存储数据时,格式化输出的方式

import json, pprintdic {name: 234, user_name: yan xia ting yu , list: [ds, a, 2], 你好这是键: 檐下听雨}print(dic)pprint.pprint(dic)print(json.dumps(dic))print(json.dumps(dic, indent2))# {name: 234, user_name: yan xia ting yu , list: [ds, a, 2], 你好这是键…

vue computed 源码分析

我们来看看computed的实现。最简单的一个demo如下&#xff1a; <html> <head><meta http-equiv"Content-Type" content"text/html; charsetutf-8" /> </head> <body> <div id"app"><div name"test&…

软件开发文档整理(之)一张示意图 | 清晰明了

在整个软件开发周期&#xff0c;开发文档是必不可少的资料&#xff0c;它们贯穿于整个开发周期&#xff0c;用来评估计划、规划进度、项目管理、软件测试、软件发布&#xff0c;可以说至关重要。   开发文档必须归档&#xff0c;没有归档的文档作用大打折扣&#xff0c;时效性…

java大数BinInteger

当我们遇到long不行的时候就要考虑这个BinInteger了&#xff0c;因为这是只要你内存够大&#xff0c;就能输入很大的数&#xff0c;用这个处理高精度问题&#xff0c;是很容易的一件事&#xff0c;对于我这刚学java的萌新来说&#xff0c;长见识了&#xff0c;确实比C方便 BigI…

HTML页面提交TABLE

在HTML页面里&#xff0c;提交一个TABLE需要把TABLE的值传入变量或json格式&#xff0c;然后submit到服务端的。 思路描述&#xff1a;将table里的值取出&#xff0c;放在json中&#xff0c;赋给一个input&#xff0c;通过一个input来实现table表数据提交到服务器&#xff0c;就…

生成条形码

https://packagist.org/packages/picqer/php-barcode-generator转载于:https://www.cnblogs.com/pansidong/p/9334224.html

3.GDScript(1)概览

GDScript 是上面提到的用于Godot的主要语言。和其他语言相比&#xff0c;它与Godot高度整合&#xff0c;有许多优点&#xff1a; 简单&#xff0c;优雅&#xff0c;设计上为Lua、Python、Squirrel等语言用户所熟悉。加载和编译速度飞快。编辑器集成非常令人愉快&#xff0c;有节…

Web 前端框架分类解读

Web前端框架可以分为两类&#xff1a; JS的类库框架 JQuery.JS Angular.JS&#xff08;模型&#xff0c; scope作用域&#xff0c;controller&#xff0c;依赖注入&#xff0c;MVVM&#xff09;&#xff1a;前端MVC Vue.JS&#xff08;MVVM&#xff09;***** Reat.JS &…

async / await对异步的处理

虽然co是社区里面的优秀异步解决方案&#xff0c;但是并不是语言标准&#xff0c;只是一个过渡方案。ES7语言层面提供async / await去解决语言层面的难题。目前async / await 在 IE edge中已经可以直接使用了&#xff0c;但是chrome和Node.js还没有支持。幸运的是&#xff0c;b…

《SQL Server 2008从入门到精通》--20180717

目录 1.触发器1.1.DDL触发器1.2.DML触发器1.3.创建触发器1.3.1.创建DML触发器1.3.2.创建DDL触发器1.3.3.嵌套触发器1.3.4.递归触发器1.4.管理触发器1.触发器 触发器是一种特殊的存储过程&#xff0c;与表紧密关联。 1.1.DDL触发器 当服务器或数据库中发生数据定义语言&#xff…