用C語(yǔ)言的泛型實(shí)現(xiàn)交換兩個(gè)變量值
第一種,最常用的是創(chuàng)建一個(gè)中間變量來(lái)循環(huán)交換它們的值:
T a = ...; T b = ...; . T tmp = a; a = b; a = tmp;
我們稱這種策略p99_swap1
。在這里,編譯器必須嚴(yán)格實(shí)現(xiàn)三個(gè)任務(wù)的順序,否則,由此程序產(chǎn)生的結(jié)果將是不正確的。
第二種,叫它p99_swap2
,試圖做類似的事情,但放松一些順序約束:
T a = ...; T b = ...; . T tmpa = a; T tmpb = b; a = tmpb; b = tmpa;
用更多的資源(棧空間或寄存器)可以產(chǎn)生更有效的代碼。兩個(gè)對(duì)象可以平行地加載和保存。但收益可能只在小對(duì)象上可以看到。所以將兩者結(jié)合起來(lái)是一個(gè)可能的嘗試
#define P99_SWAP(A, B) (sizeof(A) > sizeof(uintmax_t) ? P99_SWAP1(A, B) : P99_SWAP2(A, B))
但是如何實(shí)現(xiàn)兩個(gè) “子宏” P99_SWAP1
和 P99_SWAP2(A, B)
?如果我們想使用C的宏或者函數(shù)來(lái)實(shí)現(xiàn)的難度在于僅僅是傳遞參數(shù)A和B而不知道其類型,所以讓我們先寫函數(shù)和宏,忘記類型問(wèn)題:
inline void p00_swap2(void* a, void* b, void* tmpa, void* tmpb, size_t len) { memcpy(tmpa, a, len); memcpy(tmpb, b, len); memcpy(b, tmpa, len); memcpy(a, tmpb, len); } #define P00X_SWAP2(A, B) p00_swap2( &(A), \ &(B), \ (char[sizeof(A)]){ [0] = 0 }, \ (char[sizeof(A)]){ [0] = 0 }, sizeof(A))
這個(gè)古怪的表達(dá)式: (char[sizeof(A)]){ [0] = 0 }
被稱為復(fù)合文字(C99新特性),為復(fù)制操作提供臨時(shí)對(duì)象。
這有幾個(gè)缺點(diǎn)。首先,我們甚至沒有檢查是否A和B與對(duì)象具有相同的大小,但我們很愉快地復(fù)制到他們。因此,首先,我們必須斷言它們至少具有相同的大小,避免引起不確定的行為。這樣就可以為兩個(gè)復(fù)合文字實(shí)現(xiàn)一些表達(dá)上的魔法:
(char[sizeof(A)]){ [(intmax_t)sizeof(A) - sizeof(B)] = 0 }
其中:intmax_t
類型指定一個(gè)最大尺寸有符號(hào)整數(shù)
這里發(fā)生了什么?右邊的[]里面,一個(gè)指定的初始值,被用來(lái)初始化字符數(shù)組中的一個(gè)元素?,F(xiàn)在我們將比較兩者的大小:如果兩者相等,則表示位置0處的元素,如果sizeof(A) < sizeof(B)
,類型轉(zhuǎn)換 intmax_t
在編譯的期間將產(chǎn)生一個(gè)負(fù)數(shù)。
如果現(xiàn)在我們將上面的策略應(yīng)用于第二個(gè)復(fù)合文字,我們得到一個(gè)宏,在它調(diào)用兩個(gè)相同大小的對(duì)象的時(shí)候成功編譯,并在大小不同的時(shí)候在編譯期間產(chǎn)生錯(cuò)誤:
#define P00_SWAP2(A, B) p00_swap2( \ &(A), \ &(B), \ (char[sizeof(A)]){ [(intmax_t)sizeof(A) - sizeof(B)] = 0 }, \ (char[sizeof(B)]){ [(intmax_t)sizeof(B) - sizeof(A)] = 0 }, \ sizeof(A))
這現(xiàn)在已經(jīng)是更安全,但也許還不夠安全,因?yàn)檫@兩個(gè)對(duì)象可能有相同的大小,但仍然不是同一類型。我們可以做一個(gè)額外的檢查來(lái)確定這兩種類型是否是兼容的。這可以通過(guò)下面這樣的可能第一眼看起來(lái)有點(diǎn)hack
(1 ? &(A) : ((A = B), NULL)) #define P99_SWAP(A, B) (sizeof(A) > sizeof(uintmax_t) ? P99_SWAP1(A, B) : P99_SWAP2(A, B))
這里的條件總是真,所以它總是等于&(A)。第二個(gè)“假”部分在運(yùn)行時(shí)從未執(zhí)行,但只用來(lái)檢查它是否是正確的C代碼。如果A和B不會(huì)兼容,則表示不是正確的C代碼。
以上就是這篇文章的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)和工作能帶來(lái)幫助,如果有疑問(wèn)可以留言交流。
相關(guān)文章
C語(yǔ)言進(jìn)階輸入輸出重定向與fopen函數(shù)使用示例詳解
這篇文章主要為大家介紹了C語(yǔ)言進(jìn)階輸入輸出重定向與fopen函數(shù)的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-02-02C++關(guān)鍵字thread_local學(xué)習(xí)筆記
這篇文章主要為大家介紹了C++關(guān)鍵字thread_local學(xué)習(xí)筆記,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10c語(yǔ)言鏈表基本操作(帶有創(chuàng)建鏈表 刪除 打印 插入)
這篇文章主要介紹了c語(yǔ)言鏈表基本操作,大家參考使用吧2013-12-12C++11的for循環(huán),以及范圍Range類的簡(jiǎn)單實(shí)現(xiàn)
下面小編就為大家?guī)?lái)一篇C++11的for循環(huán),以及范圍Range類的簡(jiǎn)單實(shí)現(xiàn)。小編覺得挺不錯(cuò)的, 現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-06-06strcat函數(shù)與strncat函數(shù)的深入分析
本篇文章是對(duì)strcat函數(shù)與strncat函數(shù)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05C++中Lambda表達(dá)式的語(yǔ)法與實(shí)例
C++ 11 中的 Lambda 表達(dá)式用于定義并創(chuàng)建匿名的函數(shù)對(duì)象,以簡(jiǎn)化編程工作,下面這篇文章主要給大家介紹了關(guān)于C++中Lambda表達(dá)式的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2021-10-10