[英]What means of this code in C qsort?
void qsort (void *a, size_t n, size_t es, int (*compare)(const void *, const void *)
其中a是數組地址的開始,n是sizeof數組,es是sizeof數組元素。
我閱讀了用C語言無法理解的qsort的源代碼。 代碼如下。
#define SWAPINT(a,es) swaptype = ((char*)a- (char*)0 % sizeof(long) || \
es % sizeof(long) ? 2: es == sizeof(long)? 0 : 1
我通過解釋這個宏
if(((char*)a- (char*)0)% sizeof(long))==1 || es % sizeof(long)==1)
swaptype = 2;
else if(es== sizeof(long))
swaptype = 0;
else
swaptype = 1;
但是我不明白為什么要執行類型轉換(char *)a。
這條線是什么意思?
(char*)a- (char*)0)% sizeof(long)==1
無論在哪里找到該代碼,都可能會錯誤地復制它。 我在Canu的libutil
找到了一些非常相似的代碼:
c.swaptype = ((char *)a - (char *)0) % sizeof(long) || \
es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
該代碼可能是從FreeBSD的libc中非法復制的(因為違反了版權許可的條款):
//__FBSDID("$FreeBSD: src/lib/libc/stdlib/qsort.c,v 1.12 2002/09/10 02:04:49 wollman Exp $");
因此,我猜您是從* BSD libc實現中獲得的。 實際上,FreeBSD的quicksort實現包含SWAPINIT
宏 (不是SWAPINT
):
#define SWAPINIT(TYPE, a, es) swaptype_ ## TYPE = \
((char *)a - (char *)0) % sizeof(TYPE) || \
es % sizeof(TYPE) ? 2 : es == sizeof(TYPE) ? 0 : 1;
解析后,您應該發現上面的代碼與
condition_one = ((char *)a - (char *)0) % sizeof(long);
condition_two = es % sizeof(long);
condition_three = es == sizeof(long);
c.swaptype = (condition_one || condition_two) ? 2 : condition_three ? 0 : 1;
需要注意的是condition_two
,作為條件, 是不一樣的es % sizeof(long) == 1
,而是es % sizeof(long) != 0
。 除此之外,您的翻譯是正確的。
這些條件的意圖似乎如下:
a
不long
對齊時, condition_one
為true
。 es
不是long
的倍數時, condition_two
為true
。 es
完全long
時, condition_three
為true
。 結果是,
swaptype == 2
是當您沒有足夠的元素保證交換聰明時, swaptype == 1
適用於具有沿long
邊界對齊的元素的數組(注意:但不一定與 long 對齊 !),以及 swaptype == 0
用於與前面的描述匹配的數組,這些數組也具有long
尺寸的元素。 在這種情況下,存在顯式類型轉換,因為a
類型為void*
, 其類型算術未定義 。 但是,還要注意, ((char *)a - (char *)0)
也未定義:
當減去兩個指針時,兩個指針都將指向同一數組對象的元素,或者指向數組對象的最后一個元素之后的元素; 結果是兩個數組元素的下標不同。
(C11 N1570草案第6.5.6節第93和94頁的第9條)
它在C11中沒有明確說明,但是空指針與a
指向的對象不在同一數組中,因此違反了指針算術的基本規則,因此行為未定義。
宏正嘗試使用C語言移植檢查對齊方式,而C語言實際上並不允許進行這種測試。 因此,我們從指針中減去空指針以獲得一個整數,然后取一個long型的模數。 如果結果為零,則數據是長對齊的,我們可以訪問long。 如果不是,我們可以嘗試其他方案。
正如評論所說,因為它涉及到計算你目前的宏定義不擴展到有效的C代碼(char*)0 % sizeof(long)
,其中的左手操作數%
有鍵入char *
。 那不是整數類型,但是%
兩個操作數都必須具有整數類型。
此外,宏的擴展具有不平衡的括號。 這並不是天生的錯誤,但是使用該宏非常棘手。 此外,即使在運算符優先級產生明智結果的情況下,使用括號和額外的空格也可以幫助人工解釋代碼,而不會影響執行速度,並且可以節省很少的額外編譯成本。
因此,我認為所需的宏將更像這樣:
#define SWAPINT(a,es) swaptype = ( \
((((char*)a - (char*)0) % sizeof(long)) || (es % sizeof(long))) \
? 2 \
: ((es == sizeof(long)) ? 0 : 1)) \
)
我會考慮寫倒數第二行為
: (es != sizeof(long))
降低表達的復雜性,但以其可理解性為代價。 無論如何,目的似乎是將swaptype
設置為:
2
,如果a
沒有一個對齊n
字節邊界,其中n
是字節的數量long
,或者如果es
不是的大小的整數倍long
; 除此以外 1
如果es
不等於long
的大小; 除此以外 0
這與您的解釋類似但不完全相同。 但是請注意,由於(char*)a - (char*)0
,即使該代碼也具有未定義的行為。 僅當兩個指針都指向同一對象或剛好超過同一對象的末尾,並且(char *)0
並不指向任何對象的末尾或剛剛超過該對象的末尾時,評估這種差異才定義了行為。
您具體問過:
但是我不明白為什么要執行類型轉換(char *)a。
之所以執行此操作,是因為指針算術是根據指向的類型定義的,因此(1),一致的程序無法使用void *
進行算術,並且(2)代碼希望減法的結果相同單位是sizeof
運算符的結果(字節)。
這條線是什么意思?
(char*)a- (char*)0)% sizeof(long)==1
該行不會出現在您顯示的宏中,並且由於括號不平衡,因此它不是完整的表達式。 似乎正在嘗試確定a
點是否超出n
字節邊界,其中n
如上所定義,但同樣,評估指針差異具有不確定的行為。 還要注意,對於整數x
,在布爾上下文中評估的x % sizeof(long) == 1
與在相同上下文中評估的x % sizeof(long)
具有不同的含義。 在您描述的上下文中,后者更有意義。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.