linux核心中的min、max函數

來源:互聯網
上載者:User
這些天為了整理一下前段時間看ldd3時所學的驅動知識,所以就去看了看usb驅動。不看不知道,一看嚇一跳,裡面有很多文法我發現用的太好了,不像我們平時那樣寫代碼。裡面寫的代碼真是太好了。然而要理解到裡面的東西還是不容易的。今天看見usb_stor_access_xfer_buf函數的時候,想看看裡面的min 函數是不是按照我們寫的那麼寫。但是一看傻啦,還有些東東我還沒用過,於是趕緊google一下,那到底下面代碼是什麼樣的呢?大家可以到、include/linux/kernel.h 裡面去找。不相找事吧,那好我貼在這裡。 /*

 * min()/max() macros that also do

 * strict type-checking.. See the

 * "unnecessary" pointer comparison.

 */

#define min(x,y) ({ \

 typeof(x) _x = (x); \

 typeof(y) _y = (y); \

 (void) (&_x == &_y);  \

 _x < _y ? _x : _y; })#define max(x,y) ({ \

 typeof(x) _x = (x); \

 typeof(y) _y = (y); \

 (void) (&_x == &_y);  \

 _x > _y ? _x : _y; })  當我google 了以後發現很多人都看過這個函數,看來我是out了。這都是在大學欠下的賬啊,正所謂:“出來混,遲早都要還的”,還好今天就開始學了。 下面看一位兄弟的理解,他講的很好。http://blog.chinaunix.net/u/24474/showart_1101969.html min宏定義探究

在GCC的文檔中建議使用如下的min宏定義:
引用:#define min(X,Y)  \
(__extension__  \
({  \
   typeof(X) __x=(X), __y=(Y);   \
   (__x<__y)?__x:__y;  \
}) \



本文討論了這樣作法的意義。
    1、傳統的min帶來的副作用
    2、GCC中的({statement list})的擴充
    3、typeof(expression)
    4、__extension__的含義
    5、使用typeof和({})實現min,避免了副作用


附錄1、舊版本的的GCC中的的解決方案

附錄2、C++中使用template的解決方案


1、傳統的min帶來的副作用


min通常被定義成這樣的宏:

#define min(X,Y) ((X) < (Y) ? (X) : (Y))


這種定義會帶來一些副作用,看下面的例子:


int x = 1, y = 2;

int main()

{

   printf("min=%d\n", min(x++, y++));

   printf("x = %d, y = %d\n", x, y);

}


執行完min(x++、y++),我們期望x的值為2,y的值為3。


但是,實際的結果是,執行完mini(x++、y++)後,x的值為3,y的值為3,原因在於宏展開後x++被執行了兩次:


引用:

int x = 1, y = 2;

int main()

{

   printf("min=%d\n", x++ < y++ ? x++ : y++);

   printf("x = %d, y = %d\n", x, y);

}


2、GCC中的({statement list})的擴充

({statement list})是一個運算式,逗號運算式類似,但是功能更強,({與})中可以包含有多條語句(可以是變數定義、複雜的控制語句),該運算式的值為statement list中最後一條語句的值,舉例:


int main()

{

    int result = ({

     int i, sum = 0;

     for (i = 1; i <= 100; i++)

          sum+= i;

     sum;

    })


    printf("result=%d\n", result);

}


運行結果:

result=5050


3、typeof(expression)
typeof(expression)用來擷取expression的類型,舉例:


int main()

{

   int integer;

   typeof(100) i;  /* 運算式100的類型是int,定義了int型變數i */

   typeof(integer) j; /* 運算式integer的類型是int,定義了int型變數j */


   i = 1;

   j = 2;

}


4、__extension__的含義
GCC引入了很多標準C中的沒有的擴充,如({和)},GCC提供了pednatic選項用於檢測程式是否使用了GCC的擴充,當使用pedantic選項編譯如下程式時


int main()

{

    int result = ({

     int i, sum = 0;

     for (i = 1; i <= 100; i++)

          sum+= i;

     sum;

    })


   printf("result=%d\n", result);

}


編譯器發出警告:

$ cc -pedantic test.c

test.c: 在函數 ‘main’ 中:

test.c:9: 警告:ISO C 不允許在運算式中使用花括弧組


編譯器提醒程式員,這段C程式使用了不符合ISO C標準的文法,如果使用其他的編譯器(非GCC)編譯這段代碼有能會出錯。在所有使用GNU 擴充關鍵字的運算式之前加__extension__ 關鍵字後,使用pedantic選項編譯時間,編譯器就不再發出警告資訊:


int main()

{

    int result = __extension__({

      int i, sum = 0;

      for (i = 1; i <= 100; i++)

        sum+= i;

      sum;

    })


    printf("result=%d\n", result);

}


$ cc -pedantic test.c

$ 編譯成功!


5、使用typeof和({})實現min,避免了副作用


#define min(X,Y) \

({  \

typeof(X) __x=(X), __y=(Y);  \

(__x<__y)?__x:__y;  \

})


使用傳統的min會出現問題的例子:


int x = 1, y = 2;;

int main()

{

   printf("min=%d\n", min(x++, y++));

   printf("x = %d, y = %d\n", x, y);

}


它被擴充為

引用:

int x = 1, y = 2;;

int main()

{

   printf("min=%d\n", ({

       typeof(x) __x = (x++), __y = (y++);  /* 定義了兩個整形變數 */

       (__x<__y)?__x:__y; 

   })

   );

   printf("x = %d, y = %d\n", x, y);

}



在執行min(x++, y++)期間,x++和y++只執行了一次,因而結果是正確的。


附錄1、舊版本的的GCC中的的解決方案

舊版本的GCC提供了兩個內建的運算操作符:<?和>?, <?返回兩個運算元中較小的一個,>?返回兩個運算元中較大的一個,使用這兩個操作符定義的min如下:


#define min(x, y) ((x) <? (y))

#define max(x, y) ((x) >? (y))

但是新版本的GCC文檔中宣稱:現在這兩個運算操作符已經過時了,建議大家不要使用。


附錄2、C++中使用template的解決方案
template <class type>
type min(type a, type b)
{
     return a < b ? a : b;
}



add linux kernel min, max define:

include/linux/kernel.h

/*
 * min()/max() macros that also do
 * strict type-checking.. See the
 * "unnecessary" pointer comparison.
 */
#define min(x,y) ({ \
        typeof(x) _x = (x);     \
        typeof(y) _y = (y);     \
        (void) (&_x == &_y);            \
        _x < _y ? _x : _y; })

#define max(x,y) ({ \
        typeof(x) _x = (x);     \
        typeof(y) _y = (y);     \
        (void) (&_x == &_y);            \
        _x > _y ? _x : _y; })

   Min和Max宏: 

  

  /*

  * min()/max() macros that also do

  * strict type-checking.. See the

  * "unnecessary" pointer comparison.

  */

  #define min(x,y) ({ typeof(x) _x = (x); typeof(y) _y = (y); (void) (&_x == &_y); _x < _y ? _x : _y; })

  #define max(x,y) ({ typeof(x) _x = (x); typeof(y) _y = (y); (void) (&_x == &_y); _x > _y ? _x : _y; })

  /*

  * ..and if you can't take the strict

  * types, you can specify one yourself.

  *

  * Or not use min/max at all, of course.

  */

  #define min_t(type,x,y) ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })

  #define max_t(type,x,y) ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })

  不是感覺跟我們用的有些不一樣啊: 

  (void) (&_x == &_y); 

  (void) (&_x == &_y)這句話本身都執行程式來講完全是一句廢話,它的作用在於,本身我們無法做這樣的操作typeof(_x)==typeof(_y),所以故意判斷他們2個的地址指標是否相等,顯然是不可能相等,但是如果_x和_y的類型不一樣,其指標類型也會不一樣,2個不一樣的指標類型進行比較操作,會拋出一個編譯警告。也就是說char *p; int *q; 然後p==q;,這個判斷因為一個是char*一個是int*,會在編譯時間產生一個warning。巧妙就巧妙在這裡。 

  由於核心是很多開發著一起開發的,其中還有一些其他的實現,就跟我們平常用的一樣: 

  #define min(a,b) (((a) < (b)) ? (a) : (b)) 

  試想: 

  min(++a,++b) ==> ((++a)<(++b))?(++a):(++b) 

  是不是就有問題了,傳入的參數被加了兩次。
  好了,我就是把別人的東西收集了一下,到現在你明白裡面的GCC中的({statement list})的擴充了嗎,應該基本可以理解了。接著努力,路漫漫其修遠兮,、、、、、原文地址:http://blog.chinaunix.net/uid-23247212-id-99921.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.