簡體   English   中英

C qsort中此代碼的含義是什么?

[英]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 除此之外,您的翻譯是正確的。


這些條件的意圖似乎如下:

  • along對齊時, condition_onetrue
  • es不是long的倍數時, condition_twotrue
  • es完全long時, condition_threetrue

結果是,

  • 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM