我們從C語言開始就學(xué)會了用 % 來格式化輸出字符串淆攻,這看起來非常簡單自然。
在iOS開發(fā)時(shí)我們依然會用到它嘿架。但是我敢肯定很多人其實(shí)并不知道format到底是按照什么邏輯來識別參數(shù)并正確輸出的瓶珊。
下面我姑且使用Swift來做例子說明。
眾所周知耸彪,在 Swift 里伞芹,我們使用 print 是支持字符串插值的,這樣,我們就可以不借助于占位符唱较,也不用再去記憶類型所對應(yīng)的字符表示扎唾,就能很簡單地輸出各種類型的字符串描述了。
let a:Int = 1
let b:Float = 2.22
let c:String = "hello"
print("\(a) \(b) \(c)") // 不需要 %d %f %s 這樣的格式化
但是有些場景還是需要%格式化的南缓,比如我們需要得到一個這樣的時(shí)間間隔字符串:
08:30 - 11:40 //時(shí)間間隔
這個時(shí)候直接使用字符串插值
的方式就比較麻煩了胸遇,此時(shí)還是要借助%來格式化,于是我們這樣測試:
//iphon6 測試
let h1: Int = 8
let m1: Int = 30
let h2: Int = 11
let m2: Int = 40
let str = String(format: "%02d:%02d - %02d:%02d", h1, m1, h2, m2)
print(str) //輸出08:30 - 11:40
沒毛病西乖,接下來我們故意把上面的Int改成Int64試試
//iphon6 測試
let h1: Int64 = 8
let m1: Int64 = 30
let h2: Int64 = 11
let m2: Int64 = 40
let str = String(format: "%02d:%02d - %02d:%02d", h1, m1, h2, m2)
print(str) //輸出08:30 - 11:40
也沒毛病狐榔,別急,我們把這代碼運(yùn)行到 iphone5上試試获雕,你們猜結(jié)果是啥薄腻?想10秒鐘
0
1
2
3
4
5
6
7
8
9
OK, 公布答案:
輸出的是:
08:00 - 30:00
猜對了嗎届案?
看到這樣的結(jié)果估計(jì)大家都能看出端倪了吧庵楷,這30明顯是m1的值,卻出現(xiàn)在h2的位置楣颠。
那么為啥在iphon6尽纽、iphoneX,甚至iphone5s上都沒問題呢童漩?
原來蘋果從iphone5s之后開始全線升級為64位系統(tǒng)了弄贿,所以問題就出現(xiàn)在32位系統(tǒng)與64位系統(tǒng)的區(qū)別。
于是矫膨,我大膽猜測:
%格式化 其實(shí)并不是跟后面的參數(shù)一一對應(yīng)的差凹,而是將后面參數(shù)按字節(jié)排起來,然后按照%后面的格式所需的字節(jié)數(shù)依次取的
帶著這種猜測我們繼續(xù)實(shí)驗(yàn)侧馅, 還在iphone5上測試危尿,我們把%d 改成%lld:
let str = String(format: "%02lld:%02lld - %02lld:%02lld", h1, m1, h2, m2)
print(str) //輸出08:30 - 11:40
果然對了,因?yàn)?lld是取long long類型的馁痴,在32位上long long是8字節(jié)的谊娇,剛好對應(yīng)Int64的64位。
為了進(jìn)一步驗(yàn)證我的猜想罗晕,我們換一個測試:
//iphone5 測試
let h1: Int64 = 8
let m1: Int64 = 30
let h2: Int64 = 11
let m2: Int64 = 40
let str = String(format: "%02d:%02d - %02d:%02d", h1, m1 )//注意這里只有兩個參數(shù)
print(str) //輸出08:00 - 30:00
看到?jīng)]济欢,我們有4個 %,但只有2個參數(shù)居然沒有報(bào)錯小渊,這印證了我的猜想船逮。
其實(shí),上面這種格式化類型和實(shí)際類型不匹配以及參數(shù)個數(shù)不夠的情況應(yīng)該有warnning 或者error提示的粤铭,然而Swift都沒有挖胃,OC會有warnning提示,同理,C語言也會有Warnning酱鸭, 從這一點(diǎn)看吗垮,Swift的語法檢查不如OC的嚴(yán)格。
好了凹髓,看到這里你應(yīng)該明白了吧烁登!
Really?
再回頭看看開始的那個例子:
//iphon6 測試
let h1: Int64 = 8
let m1: Int64 = 30
let h2: Int64 = 11
let m2: Int64 = 40
let str = String(format: "%02d:%02d - %02d:%02d", h1, m1, h2, m2)
print(str) //輸出08:30 - 11:40
有沒有疑問呢蔚舀?
我當(dāng)時(shí)是有疑問的饵沧,按說%d應(yīng)該是想格式化Int類型的,那為什么在64位的iphone6上 可以正確地輸出Int64的值呢赌躺?難道在64位的iOS系統(tǒng)中Int是64位的狼牺?
按照以前的Linux系統(tǒng)的經(jīng)驗(yàn),64位系統(tǒng)應(yīng)該只是說指針是64位(8字節(jié))的礼患,Int還是32位的啊是钥。于是我查找了Swift中Int的定義:
原來如此,iOS的64位系統(tǒng)中Int是64位的缅叠,所以上面%d取的也是64位的悄泥,也就沒問題了。
這個跟一般的類Unix系統(tǒng)是不一樣的肤粱,我們看下面這張圖:
其中弹囚,
I表示:int類型
L表示:long類型
P表示:pointer指針類型
32表示:32位系統(tǒng)
64表示64位系統(tǒng)
如:LP64表示,在64位系統(tǒng)下的long類型和pointer類型長度為64位领曼。
64位Linux 使用了 LP64 標(biāo)準(zhǔn)余寥,即:long類型和pointer類型長度為64位,int還是32位的悯森。
由上可知iOS系統(tǒng)( Darwin Mach 內(nèi)核)是使用了ILP64標(biāo)準(zhǔn)。
這次真的明白了吧绪撵!