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.pswp.cn/news/249941.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/249941.shtml
英文地址,請注明出處:http://en.pswp.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…