CoreFoundation框架詳細(xì)解析(四) —— 內(nèi)存管理(二)

版本記錄

版本號 時間
V1.0 2017.10.07

前言

Core Foundation框架(CoreFoundation.framework)是一組C語言接口,它們?yōu)閕OS應(yīng)用程序提供基本數(shù)據(jù)管理和服務(wù)功能否副。接下來我們就詳細(xì)的解析這個框架。感興趣的可以看我上面寫的幾篇典阵。
1. CoreFoundation框架詳細(xì)解析(一) —— 基本概覽
2. CoreFoundation框架詳細(xì)解析(二) —— 設(shè)計概念
3. CoreFoundation框架詳細(xì)解析(三) —— 內(nèi)存管理(一)

Core Foundation Object Lifecycle Management - Core Foundation對象生命周期管理

感興趣的可以看一下這里

Core Foundation對象的使用壽命取決于其引用計數(shù) - 希望對象持久存在的客戶端數(shù)量的內(nèi)部計數(shù)良狈。 在Core Foundation中創(chuàng)建或復(fù)制對象時张足,其引用計數(shù)設(shè)置為1。 隨后的客戶端可以通過調(diào)用CFRetain來聲明對象的所有權(quán)瘟滨,CFRetain會增加引用計數(shù)候醒。 后來,當(dāng)你沒有更多的使用對象九火,你調(diào)用CFRelease晋涣。 當(dāng)引用計數(shù)達(dá)到0時洲敢,對象的分配器釋放對象的內(nèi)存。

1. Retaining Object References - 保留對象引用

要增加Core Foundation對象的引用計數(shù)敌土,請將對該對象的引用傳遞給CFRetain函數(shù)的參數(shù):

/* myString is a CFStringRef received from elsewhere */

myString = (CFStringRef)CFRetain(myString);

2. Releasing Object References - 釋放對象引用

要減少Core Foundation對象的引用計數(shù),請將對該對象的引用傳遞給CFRelease函數(shù)的參數(shù):

CFRelease(myString);

重要提示:您不應(yīng)該直接釋放Core Foundation對象(例如运翼,通過對它調(diào)用free)返干。 完成對象后,調(diào)用CFRelease功能南蹂,Core Foundation將正確處理它犬金。

3. Copying Object References - 復(fù)制對象引用

當(dāng)您復(fù)制對象時,生成的對象的引用計數(shù)為1六剥,而不考慮原始對象的引用計數(shù)晚顷。 有關(guān)復(fù)制對象的更多信息,請參閱Copy Functions疗疟。

4. Determining an Object's Retain Count - 確定對象的保留計數(shù)

如果您想知道Core Foundation對象的當(dāng)前引用計數(shù)该默,則將對該對象的引用傳遞給CFGetRetainCount函數(shù)的參數(shù):

CFIndex count = CFGetRetainCount(myString);

但是請注意,除了調(diào)試之外策彤,通常不需要確定Core Foundation對象的引用計數(shù)栓袖。 如果您發(fā)現(xiàn)自己需要知道對象的保留計數(shù),請檢查您是否正確遵守所有權(quán)政策規(guī)則(請參閱Ownership Policy)店诗。


Copy Functions - 復(fù)制函數(shù)

通常裹刮,當(dāng)使用=運(yùn)算符將一個變量的值分配給另一個變量時,會發(fā)生標(biāo)準(zhǔn)復(fù)制操作(也可能稱為簡單賦值)庞瘸。例如捧弃,表達(dá)式myInt2 = myInt1會使myInt1的整數(shù)內(nèi)容從myInt1使用的內(nèi)存復(fù)制到myInt2使用的內(nèi)存中。在復(fù)制操作之后,兩個獨(dú)立的內(nèi)存區(qū)域包含相同的值违霞。但是嘴办,如果您嘗試以這種方式復(fù)制Core Foundation對象,請注意买鸽,您不會重復(fù)對象本身涧郊,僅僅是對對象的引用。

例如眼五,Core Foundation的新用戶可能會認(rèn)為要創(chuàng)建CFString對象的副本妆艘,她將使用表達(dá)式myCFString2 = myCFString1。同樣看幼,此表達(dá)式實(shí)際上并不復(fù)制字符串?dāng)?shù)據(jù)双仍。因為myCFString1和myCFString2都必須具有CFStringRef類型,所以此表達(dá)式僅復(fù)制對該對象的引用桌吃。復(fù)制操作后朱沃,您有兩份CFString的引用。這種類型的副本非趁┯眨快逗物,因為只有引用是重復(fù)的,但重要的是要記住以這種方式復(fù)制可變對象是危險的瑟俭。與使用全局變量的程序一樣翎卓,如果應(yīng)用程序的一部分使用引用的副本更改對象,那么程序的其他具有該引用副本的部分就無法知道數(shù)據(jù)已更改摆寄。

如果要復(fù)制對象失暴,則必須使用Core Foundation提供的函數(shù)之一專門用于此目的。繼續(xù)使用CFString示例微饥,您將使用CFStringCreateCopy創(chuàng)建一個包含與原始數(shù)據(jù)相同的數(shù)據(jù)的全新CFString對象逗扒。具有CreateCopy函數(shù)的Core Foundation類型還提供了可以修改的對象的副本CreateMutableCopy的變體。

1. Shallow Copy - 淺拷貝

復(fù)制復(fù)合對象欠橘,可以包含其他對象的集合對象等對象也必須小心處理矩肩。正如您所期望的,使用=運(yùn)算符對這些對象執(zhí)行副本會導(dǎo)致對象引用的重復(fù)肃续。與CFStringCFData這樣的簡單對象相反黍檩,為復(fù)合對象(如CFArray和CFSet)提供的CreateCopy函數(shù)實(shí)際上會執(zhí)行淺拷貝。在這些對象的情況下始锚,淺層復(fù)制意味著創(chuàng)建新的集合對象刽酱,但是原始集合的內(nèi)容不會被復(fù)制 - 只有對象引用被復(fù)制到新的容器。如果您有一個不可變的數(shù)組瞧捌,并且您想對其進(jìn)行重新排序棵里,則此類型的副本很有用。在這種情況下,您不想復(fù)制所有包含的對象衍慎,因為不需要更改它們,以及為什么要使用額外的內(nèi)存皮钠?您只需要更改包含的對象集稳捆。與使用簡單類型復(fù)制對象引用相同的風(fēng)險也適用。

2. Deep Copy - 深拷貝

當(dāng)您要創(chuàng)建一個全新的復(fù)合對象時麦轰,必須執(zhí)行深層復(fù)制乔夯。 深層復(fù)制復(fù)制復(fù)合對象及其所有對象的內(nèi)容。 Core Foundation的當(dāng)前版本包括執(zhí)行屬性列表深度復(fù)制的函數(shù)(請參閱CFPropertyListCreateDeepCopy)款侵。 如果要創(chuàng)建其他結(jié)構(gòu)的深層副本末荐,則可以通過遞歸遞減到復(fù)合對象并逐個復(fù)制其所有內(nèi)容來執(zhí)行深層副本。 當(dāng)復(fù)合對象可以遞歸時新锈,請注意實(shí)現(xiàn)此功能 - 它們可以直接或間接包含對其自身的引用 - 這可能導(dǎo)致遞歸循環(huán)甲脏。


Byte Ordering - 字節(jié)排序

微處理器架構(gòu)通常使用兩種不同的方法將多字節(jié)數(shù)字?jǐn)?shù)據(jù)的各個字節(jié)存儲在存儲器中。這種差異被稱為byte orderingendian nature妹笆。大多數(shù)情況下块请,您的計算機(jī)的端序格式可以被安全地忽略,但在某些情況下拳缠,它變得至關(guān)重要墩新。 OS X提供了一種將數(shù)據(jù)的一種端形式轉(zhuǎn)化為另外一種端模式的各種函數(shù)。

Intel x86處理器首先存儲最低有效字節(jié)的雙字節(jié)整數(shù)窟坐,后跟最高有效字節(jié)海渊。這稱為小端字節(jié)排序。其他CPU(如PowerPC CPU)首先存儲其最高有效字節(jié)的雙字節(jié)整數(shù)哲鸳,后跟其最低有效字節(jié)臣疑。這被稱為大字節(jié)字節(jié)排序。大多數(shù)時候徙菠,您的計算機(jī)的端序格式可以安全地忽略朝捆,但在某些情況下,它變得至關(guān)重要懒豹。例如芙盘,如果您嘗試從與您的端點(diǎn)性質(zhì)不同的計算機(jī)上創(chuàng)建的文件讀取數(shù)據(jù),則字節(jié)排序的差異可能會產(chǎn)生不正確的結(jié)果脸秽。從網(wǎng)絡(luò)讀取數(shù)據(jù)時也會發(fā)生同樣的問題儒老。

術(shù)語:術(shù)語big-endianlittle-endian來自Jonathan Swift的十八世紀(jì)諷刺Gulliver的旅行。 Blefuscu帝國的主體被分為兩個派系:從大端開始吃蛋的人和從小端起吃蛋的人记餐。

給出一個討論端格式問題的具體例子驮樊,考慮一個簡單的C結(jié)構(gòu)的例子,它定義了兩個四字節(jié)整數(shù),如Listing 1所示囚衔。

// Listing 1  Example data structure

struct {
    UInt32 int1;
    UInt32  int2;
} aStruct;

假設(shè)Listing 2中所示的代碼用于初始化Listing 1所示的結(jié)構(gòu)挖腰。

// Listing 2  Initializing the example structure

ExampleStruct   aStruct;
 
aStruct.int1 = 0x01020304;
aStruct.int2 = 0x05060708;

考慮Figure 1中的圖表,其中顯示了大端處理器或內(nèi)存系統(tǒng)如何組織示例數(shù)據(jù)练湿。 在大端系統(tǒng)中猴仑,物理內(nèi)存被組織,每個字節(jié)的地址從最高到最低的肥哎。

Figure 1 Example data in big-endian format

請注意辽俗,這些字段存儲在左側(cè)的更高有效字節(jié)和右側(cè)較少有效字節(jié)。 這意味著地址字段Int1的最高有效字節(jié)的地址是0x98篡诽,而地址0x9B對應(yīng)于Int1的最低有效字節(jié)崖飘。

圖2中的圖表顯示了一個小端系統(tǒng)如何組織數(shù)據(jù)。

Figure 2 Example data in little-endian format

請注意杈女,每個字段的最低地址現(xiàn)在對應(yīng)于最低有效字節(jié)朱浴,而不是最高有效字節(jié)。如果要在小端系統(tǒng)上打印Int1的值达椰,您將看到盡管以不同的字節(jié)順序存儲赊琳,但它仍然被正確解釋為十進(jìn)制值16909060。

現(xiàn)在假設(shè)由Listing 2所示的代碼初始化的示例數(shù)據(jù)值是在小端系統(tǒng)上生成并保存到磁盤砰碴。假設(shè)數(shù)據(jù)以字節(jié)地址順序?qū)懭氪疟P躏筏。當(dāng)通過大端系統(tǒng)從磁盤讀取時,數(shù)據(jù)將再次布置在存儲器中呈枉,如Figure 2所示趁尼。問題是數(shù)據(jù)仍然是小端字節(jié)順序,即使它是在大型端系統(tǒng)猖辫。該差異導(dǎo)致值被錯誤評估酥泞。在本示例中,Int1域的十進(jìn)制值應(yīng)為16909060啃憎,但是由于字節(jié)排序不正確芝囤,因此它被評估為67305985.這種現(xiàn)象稱為字節(jié)交換,一般發(fā)生在當(dāng)一個端格式的數(shù)據(jù)被使用其他字符串格式時辛萍。

不幸的是悯姊,這是一般情況下無法解決的問題。原因是您交換的方式取決于數(shù)據(jù)的格式贩毕。字符串通常不會被交換悯许,長字交換四字節(jié)到端,字交換兩個字節(jié)端到端辉阶。因此先壕,需要交換數(shù)據(jù)的任何程序必須知道數(shù)據(jù)類型瘩扼,源數(shù)據(jù)端序和主機(jī)端序。

CFByteOrder.h中的函數(shù)允許您對雙字節(jié)和四字節(jié)整數(shù)以及浮點(diǎn)值進(jìn)行字節(jié)交換垃僚。適當(dāng)使用這些功能可以幫助您確保程序操作的數(shù)據(jù)正確集绰。有關(guān)使用這些函數(shù)的詳細(xì)信息,請參閱Byte Swapping 部分谆棺。 請注意栽燕,Core Foundation的字節(jié)交換函數(shù)僅適用于OS X。


Using Allocators in Creation Functions - 在創(chuàng)建函數(shù)中使用分配器

每個Core Foundation不透明類型都有一個或多個創(chuàng)建函數(shù)包券,該函數(shù)創(chuàng)建并返回以特定方式初始化的該類型的對象。所有創(chuàng)建函數(shù)都將其作為第一個參數(shù)作為對分配器對象(CFAllocatorRef)的引用炫贤。某些函數(shù)也可能具有用于專門分配和釋放目的的分配器參數(shù)溅固。

分配器參考參數(shù)有幾個選項:

  • 你可以傳遞常量kCFAllocatorSystemDefault,這指定了通用系統(tǒng)分配器(它是初始默認(rèn)分配器)兰珍。
  • 您可以傳遞NULL來指定當(dāng)前的默認(rèn)分配器(可能是自定義分配器或通用系統(tǒng)分配器)侍郭。這與傳遞kCFAllocatorDefault相同。
  • 您可以傳遞常量kCFAllocatorNull掠河,該常量指示不分配的分配器亮元,嘗試使用它是錯誤的。一些創(chuàng)建函數(shù)具有用于重新分配或釋放后備存儲的特殊分配器的參數(shù)唠摹,通過為參數(shù)指定kCFAllocatorNull爆捞,可以防止自動重新分配或釋放。
  • 您可以使用CFGetAllocator函數(shù)獲得另一個Core Foundation對象使用的分配器的引用勾拉。通過使用相同的分配器分配它們煮甥,可以將相關(guān)對象放入內(nèi)存zone中。
  • 您可以傳遞對自定義分配器的引用(請參閱Creating Custom Allocators)藕赞。

如果要使用自定義分配器成肘,并且要使其成為默認(rèn)分配器,建議首先使用CFAllocatorGetDefault函數(shù)獲取對當(dāng)前默認(rèn)分配器的引用斧蜕,并將其存儲在局部變量中双霍。完成使用自定義分配器后,使用CFAllocatorSetDefault函數(shù)將存儲的分配器重置為默認(rèn)分配器批销。


Using the Allocator Context - 使用分配器上下文

Core Foundation中的每個分配器都有一個上下文洒闸。 上下文是定義對象的操作環(huán)境的結(jié)構(gòu),通常由函數(shù)指針組成均芽。 分配器的上下文由CFAllocatorContext結(jié)構(gòu)定義顷蟀。 除了函數(shù)指針之外,結(jié)構(gòu)還包含版本號和用戶定義數(shù)據(jù)的字段骡技。

// Listing 1  The CFAllocatorContext structure

typedef struct {
    CFIndex version;
    void * info;
    const void *(*retain)(const void *info);
    void (*release)(const void *info);
    CFStringRef (*copyDescription)(const void *info);
    void * (*allocate)(CFIndex size, CFOptionFlags hint, void *info);
    void * (*reallocate)(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info);
    void (*deallocate)(void *ptr, void *info);
    CFIndex (*preferredSize)(CFIndex size, CFOptionFlags hint, void *info);
} CFAllocatorContext;

info字段包含分配器的任何特別定義的數(shù)據(jù)鸣个。 例如羞反,分配器可以使用info字段來跟蹤特殊的分配。

重要提示:對于當(dāng)前版本囤萤,不要將version字段的值設(shè)置為0以外的任何值昼窗。

如果在分配器上下文(info字段)中有一些用戶定義的數(shù)據(jù),請使用CFAllocatorGetContext函數(shù)獲取分配器的CFAllocatorContext結(jié)構(gòu)涛舍。 然后根據(jù)需要評估或處理數(shù)據(jù)澄惊。 以下代碼提供了一個示例:

// Listing 2  Getting the allocator context and user-defined data
 
static int numOutstandingAllocations(CFAllocatorRef alloc) {
    CFAllocatorContext context;
    context.version = 0;
    CFAllocatorGetContext(alloc, &context);
    return (*(int *)(context.info));
}

其他Core Foundation函數(shù)調(diào)用在分配器上下文中定義的與內(nèi)存相關(guān)的回調(diào),并將一個無類型的指針取回或返回到一個內(nèi)存塊(void *):

  • CFAllocatorAllocate富雅,分配一個內(nèi)存塊掸驱。
  • CFAllocatorReallocate,重新分配一塊內(nèi)存没佑。
  • CFAllocatorDeallocate毕贼,取消分配一塊內(nèi)存。
  • CFAllocatorGetPreferredSizeForSize蛤奢,根據(jù)給定的一個請求鬼癣,給出了可能被分配的內(nèi)存大小。

Creating Custom Allocators - 創(chuàng)建自定義分配器

要創(chuàng)建自定義分配器啤贩,首先聲明并初始化CFAllocatorContext類型的結(jié)構(gòu)待秃。 將版本字段初始化為0,并將任何所需的數(shù)據(jù)(如控制信息)分配并分配給info字段痹屹。 此結(jié)構(gòu)的其他字段是在下面的Implementing Allocator Callbacks中描述的函數(shù)指針章郁。

一旦將適當(dāng)?shù)闹捣峙浣oCFAllocatorContext結(jié)構(gòu)的字段,則調(diào)用CFAllocatorCreate函數(shù)來創(chuàng)建allocator對象志衍。 該函數(shù)的第二個參數(shù)是指向結(jié)構(gòu)的指針驱犹。 此函數(shù)的第一個參數(shù)標(biāo)識用于為新對象分配內(nèi)存的分配器。 如果要在CFAllocateContext結(jié)構(gòu)中為此使用allocate回調(diào)足画,請為第一個參數(shù)指定kCFAllocatorUseContext常量雄驹。 如果要使用默認(rèn)分配器,請在此參數(shù)中指定NULL淹辞。

// Listing 1  Creating a custom allocator

static CFAllocatorRef myAllocator(void) {

static CFAllocatorRef allocator = NULL;

if (!allocator) {

CFAllocatorContext context =

{0, NULL, NULL, (void *)free, NULL,

myAlloc, myRealloc, myDealloc, NULL};

context.info = malloc(sizeof(int));

allocator = CFAllocatorCreate(NULL, &context);

}

return allocator;

}

1. Implementing Allocator Callbacks - 實(shí)現(xiàn)分配器回調(diào)

CFAllocatorContext結(jié)構(gòu)有七個定義回調(diào)函數(shù)的字段医舆。 如果創(chuàng)建自定義分配器,則必須至少實(shí)現(xiàn)allocate函數(shù)象缀。 分配器回調(diào)應(yīng)該是線程安全的蔬将,如果回調(diào)函數(shù)調(diào)用其他函數(shù),它們也應(yīng)該是重入的央星。

保留霞怀,釋放和復(fù)制描述回調(diào)都以CFA1locatorContext結(jié)構(gòu)的info字段為單參數(shù)。 鍵入為void *莉给,此字段指向您為分配器定義的任何數(shù)據(jù)毙石,例如包含控制信息的結(jié)構(gòu)體廉沮。

Retain 回調(diào):

const void *(*retain)(const void *info);

info中保留您為分配器上下文定義的數(shù)據(jù)。 這只有在數(shù)據(jù)是Core Foundation對象時才有意義徐矩。 您可以將此函數(shù)指針設(shè)置為NULL滞时。

Release回調(diào)

void (*release)(const void *info);

Release(或free)您為分配器上下文定義的數(shù)據(jù)。 您可以將此函數(shù)指針設(shè)置為NULL滤灯,但這樣做可能會導(dǎo)致內(nèi)存泄漏坪稽。

Copy Description回調(diào):

CFStringRef (*copyDescription)(const void *info);

返回對描述您的分配器的CFString的引用,特別是用戶定義數(shù)據(jù)的某些特性鳞骤。 您可以將此函數(shù)指針設(shè)置為NULL窒百,在這種情況下,Core Foundation將提供基本描述豫尽。

Allocate回調(diào)

void *   (*allocate)(CFIndex size, CFOptionFlags hint, void *info);

分配至少size字節(jié)的內(nèi)存塊篙梢,并返回指向塊開頭的指針。 hint參數(shù)是一個你現(xiàn)在應(yīng)該不使用的位域拂募。 size參數(shù)應(yīng)該始終大于0庭猩,如果不是窟她,或者發(fā)生分配問題陈症,返回NULL。 此回調(diào)可能不為NULL震糖。

Reallocate回調(diào)

void *   (*reallocate)(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info);

將由ptr指向的內(nèi)存塊的大小更改為由newsize指定的大小录肯,并將指針返回到較大的內(nèi)存塊。 在任何重新分配失敗時返回NULL吊说,使舊的內(nèi)存塊不變论咏。 請注意,ptr參數(shù)永遠(yuǎn)不會為NULL颁井,而newsize將始終大于0 - 除非滿足這兩個條件厅贪,否則不使用該回調(diào)。

將舊內(nèi)存塊的內(nèi)容保持不變雅宾,直到較小的新尺寸或舊尺寸养涮。 如果ptr參數(shù)不是先前由分配器分配的內(nèi)存塊,則結(jié)果未定義眉抬;異常程序終止可能發(fā)生贯吓。 hint參數(shù)是一個你現(xiàn)在應(yīng)該不使用的位域。 如果將此回調(diào)設(shè)置為NULL蜀变,則當(dāng)它嘗試使用該分配器時悄谐,CFAllocatorReallocate函數(shù)在大多數(shù)情況下返回NULL。

Deallocate回調(diào)

void   (*deallocate)(void *ptr, void *info);

使ptr指向的內(nèi)存塊可用于分配器的后續(xù)重用库北,但不可用于程序的繼續(xù)使用爬舰。 ptr參數(shù)不能為NULL们陆,如果ptr參數(shù)不是先前由allocator分配的內(nèi)存塊,則結(jié)果未定義洼专,異常程序終止可能發(fā)生棒掠。 您可以將此回調(diào)設(shè)置為NULL,在這種情況下屁商,CFAllocatorDeallocate函數(shù)不起作用烟很。

Preferred Size回調(diào)

CFIndex   (*preferredSize)(CFIndex size, CFOptionFlags hint, void *info);

返回分配器可能分配的實(shí)際大小,給出對size大小的內(nèi)存塊的請求蜡镶。 hint參數(shù)是一個你現(xiàn)在應(yīng)該不使用的位域雾袱。


Byte Swapping - 字節(jié)交換

如果您需要找到主機(jī)字節(jié)順序,您可以使用函數(shù)CFByteOrderGetCurrent官还。 可能的返回值為CFByteOrderUnknown芹橡,CFByteOrderLittleEndianCFByteOrderBigEndian

1. Byte Swapping Integers - 字節(jié)交換整數(shù)

Core Foundation為字節(jié)交換提供了三個優(yōu)化的基本功能 - CFSwapInt16望伦,CFSwapInt32CFSwapInt64林说。 所有其他交換函數(shù)都使用這些原語完成他們的工作。 一般來說屯伞,您不需要直接使用這些原語腿箩。

盡管原始交換功能無條件交換,但是較高級別的交換功能是以不需要字節(jié)交換的方式進(jìn)行定義的劣摇,換句話說珠移,當(dāng)源和主機(jī)字節(jié)順序相同時,它們不會執(zhí)行任何操作末融。 對于整數(shù)類型钧惧,這些函數(shù)采用CFSwapXXXBigToHostCFSwapXXXLittleToHostCFSwapXXXHostToBigCFSwapXXXHostToLittle的格式勾习,其中XXX是諸如Int32的數(shù)據(jù)類型浓瞪。 例如,如果您在一個小端點(diǎn)機(jī)器上讀取數(shù)據(jù)為網(wǎng)絡(luò)字節(jié)順序(big-endian)的網(wǎng)絡(luò)中的16位整數(shù)值巧婶,則可以使用函數(shù)CFSwapInt16BigToHost乾颁。 Listing 1演示了這個過程。

// Listing 1  Swapping a 16 bit Integer

SInt16  bigEndian16;
SInt16  swapped16;
 
// Swap a 16 bit value read from network.
swapped16 = CFSwapInt16BigToHost(bigEndian16);

Byte Ordering部分介紹了一個簡單的C結(jié)構(gòu)示例粹舵,該C結(jié)構(gòu)創(chuàng)建并保存到小端機(jī)上的磁盤钮孵,然后從大端機(jī)器上的磁盤讀取。 為了糾正這種情況眼滤,您必須交換每個字段中的字節(jié)巴席。 Listing 2中的代碼演示了如何使用Core Foundation字節(jié)交換函數(shù)來完成此操作。

// Listing 2  Byte swapping fields in a C structure

// Byte swap the values if necessary.
aStruct.int1 = CFSwapInt32LittleToHost(aStruct.int1)
aStruct.int2 = CFSwapInt32LittleToHost(aStruct.int2)

假設(shè)一個大端的架構(gòu)诅需,Listing 2中使用的函數(shù)將交換每個字段中的字節(jié)漾唉。 Figure 1顯示了字段交換對aStruct.int1字段的影響荧库。 請注意,字節(jié)交換代碼在小端機(jī)上運(yùn)行時不會執(zhí)行任何操作赵刑。 編譯器應(yīng)優(yōu)化代碼并保留數(shù)據(jù)不變分衫。

Figure 1 Four-byte little-endian to big-endian swap

2. Byte Swapping Floating-Point Values - 字節(jié)交換浮點(diǎn)值

即使在單個平臺上,浮點(diǎn)值也可以有許多不同的表示形式般此。 除非你非常小心蚪战,否則嘗試在平臺邊界上傳遞浮點(diǎn)值會讓人無盡的頭疼。 為了幫助您處理浮點(diǎn)數(shù)铐懊,Core Foundation定義了一組函數(shù)和兩個特殊的數(shù)據(jù)類型以及整數(shù)交換函數(shù)邀桑。 這些函數(shù)允許您對32位和64位浮點(diǎn)值進(jìn)行編碼,以便稍后對其進(jìn)行解碼科乎,并在必要時進(jìn)行字節(jié)交換壁畸。 Listing 3 顯示了如何編碼64位浮點(diǎn)數(shù),Listing 4顯示了如何解碼它茅茂。

// Listing 3  Encoding a Floating Point Value
Float64 myFloat64;

CFSwappedFloat64 swappedFloat;

// Encode the floating-point value.

swappedFloat = CFConvertFloat64HostToSwapped(myFloat64);
// Listing 4  Decoding a floating-point value

Float64             myFloat64;
CFSwappedFloat64    swappedFloat;
 
// Decode the floating-point value.
myFloat64 = CFConvertFloat64SwappedToHost(swappedFloat);

數(shù)據(jù)類型CFSwappedFloat32CFSwappedFloat64在規(guī)范表示中包含浮點(diǎn)值捏萍。 CFSwappedFloat本身不是浮點(diǎn)數(shù),不應(yīng)該直接用作浮點(diǎn)數(shù)空闲。 然而令杈,您可以發(fā)送一個到另一個進(jìn)程,保存到磁盤或通過網(wǎng)絡(luò)發(fā)送进副。 由于格式是通過轉(zhuǎn)換函數(shù)轉(zhuǎn)換為規(guī)范格式的这揣,因此不需要顯式交換API悔常。 如果需要影斑,在格式轉(zhuǎn)換過程中,會為您處理字節(jié)交換机打。

后記

未完矫户,待續(xù)~~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市残邀,隨后出現(xiàn)的幾起案子皆辽,更是在濱河造成了極大的恐慌,老刑警劉巖芥挣,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件驱闷,死亡現(xiàn)場離奇詭異,居然都是意外死亡空免,警方通過查閱死者的電腦和手機(jī)空另,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蹋砚,“玉大人扼菠,你說我怎么就攤上這事摄杂。” “怎么了循榆?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵析恢,是天一觀的道長。 經(jīng)常有香客問我秧饮,道長映挂,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任盗尸,我火速辦了婚禮袖肥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘振劳。我一直安慰自己椎组,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布历恐。 她就那樣靜靜地躺著寸癌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪弱贼。 梳的紋絲不亂的頭發(fā)上蒸苇,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機(jī)與錄音吮旅,去河邊找鬼溪烤。 笑死,一個胖子當(dāng)著我的面吹牛庇勃,可吹牛的內(nèi)容都是我干的檬嘀。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼责嚷,長吁一口氣:“原來是場噩夢啊……” “哼鸳兽!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起罕拂,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤揍异,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后爆班,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體衷掷,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年柿菩,在試婚紗的時候發(fā)現(xiàn)自己被綠了戚嗅。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖渡处,靈堂內(nèi)的尸體忽然破棺而出镜悉,到底是詐尸還是另有隱情,我是刑警寧澤医瘫,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布侣肄,位于F島的核電站,受9級特大地震影響醇份,放射性物質(zhì)發(fā)生泄漏稼锅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一僚纷、第九天 我趴在偏房一處隱蔽的房頂上張望矩距。 院中可真熱鬧,春花似錦怖竭、人聲如沸锥债。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哮肚。三九已至,卻和暖如春广匙,著一層夾襖步出監(jiān)牢的瞬間允趟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工鸦致, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留潮剪,地道東北人。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓分唾,卻偏偏與公主長得像抗碰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子鳍寂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容