『Cプログラミング診断室』目次次(第6章 不慣れ 1行80字)

第6章 不慣れ

ビットフィールド


■ダミー関数■

リスト6−5は、似たようなマクロ定義の連続で、リスト6−6がそのマクロを参照している部 分です。

 
リスト6−5 ビット処理のマクロ定義

     1	/********************************************************************************/
     2	/*                          ATTRIBUTES MODIFIED FLAGS                           */
     3	/********************************************************************************/
     4	
     5	#define MODIFIED_FLAGS_LEN      4
     6	
     7	/**********************   common window modified flags  *************************/
     8	
     9	#define WIN_FONT_MODIFIED                       (0x00000001)
    10	#define WIN_CLIENT_DATA_MODIFIED                (0x00000002)
    11	#define WIN_BELOW_MODIFIED                      (0x00000004)
    12	#define WIN_X_MODIFIED                          (0x00000008)
    13	#define WIN_Y_MODIFIED                          (0x00000010)
    14	#define WIN_VERTICAL_SCROLLBAR_MODIFIED         (0x00000020)
    15	#define WIN_LEFT_MARGIN_MODIFIED                (0x00000040)
    16	#define WIN_TOP_MARGIN_MODIFIED                 (0x00000080)
    17	#define WIN_CURSOR_MODIFIED                     (0x00000100)
    18	
    19	#define WIN_MODIFIED(_bitmask,_flags)   _flags[0] |= _bitmask
    20	
    21	#define WIN_FONT_modified(_flags) \
    22	                WIN_MODIFIED(WIN_FONT_MODIFIED,_flags)
    23	#define WIN_CLIENT_DATA_modified(_flags) \
    24	                WIN_MODIFIED(WIN_CLIENT_DATA_MODIFIED,_flags)
    25	#define WIN_BELOW_modified(_flags) \
    26	                WIN_MODIFIED(WIN_BELOW_MODIFIED,_flags)
    27	#define WIN_X_modified(_flags) \
    28	                WIN_MODIFIED(WIN_X_MODIFIED,_flags)
    29	#define WIN_Y_modified(_flags) \
    30	                WIN_MODIFIED(WIN_Y_MODIFIED,_flags)
    31	#define WIN_VERTICAL_SCROLLBAR_modified(_flags) \
    32	                WIN_MODIFIED(WIN_VERTICAL_SCROLLBAR_MODIFIED,_flags)
    33	#define WIN_LEFT_MARGIN_modified(_flags) \
    34	                WIN_MODIFIED(WIN_LEFT_MARGIN_MODIFIED,_flags)
    35	#define WIN_TOP_MARGIN_modified(_flags) \
    36	                WIN_MODIFIED(WIN_TOP_MARGIN_MODIFIED,_flags)
    37	#define WIN_CURSOR_modified(_flags) \
    38	                WIN_MODIFIED(WIN_CURSOR_MODIFIED,_flags)
    39	
    40	#define isWIN_MODIFIED(_bitmask,_flags) ((_flags[0] & (_bitmask))==(_bitmask))
    41	
    42	#define isWIN_FONT_modified(_flags) \
    43	                isWIN_MODIFIED(WIN_FONT_MODIFIED,_flags)
    44	#define isWIN_CLIENT_DATA_modified(_flags) \
    45	                isWIN_MODIFIED(WIN_CLIENT_DATA_MODIFIED,_flags)
    46	#define isWIN_BELOW_modified(_flags) \
    47	                isWIN_MODIFIED(WIN_BELOW_MODIFIED,_flags)
    48	#define isWIN_X_modified(_flags) \
    49	                isWIN_MODIFIED(WIN_X_MODIFIED,_flags)
    50	#define isWIN_Y_modified(_flags) \
    51	                isWIN_MODIFIED(WIN_Y_MODIFIED,_flags)
    52	#define isWIN_VERTICAL_SCROLLBAR_modified(_flags) \
    53	                isWIN_MODIFIED(WIN_VERTICAL_SCROLLBAR_MODIFIED,_flags)
    54	#define isWIN_LEFT_MARGIN_modified(_flags) \
    55	                isWIN_MODIFIED(WIN_LEFT_MARGIN_MODIFIED,_flags)
    56	#define isWIN_TOP_MARGIN_modified(_flags) \
    57	                isWIN_MODIFIED(WIN_TOP_MARGIN_MODIFIED,_flags)
    58	#define isWIN_CURSOR_modified(_flags) \
    59	                isWIN_MODIFIED(WIN_CURSOR_MODIFIED,_flags)
    60	
    61	/*************************      FRAME modified flags    *************************/
    62	
    63	/*************************      まだまだ続きます        *************************/

 
リスト6−6 swin_attr_set(マクロ利用版)

     1	/**
     2	 **     set attribute
     3	 **/
     4	void
     5	win_attr_set( win, ap, modified_flags )
     6	  myWindow      *win;
     7	  va_list       ap;
     8	  unsigned long *modified_flags;
     9	{
    10	        myFrame                 *frame;
    11	        myPanel                 *panel;
    12	        myCanvas                *canvas;
    13	        int                     attr;
    14	        va_short                itemp;
    15	        short                   *pointer, *oldpointer;
    16	        myPanel_Item_Choice     *point;
    17	        int                     size, len;
    18	        char                    *ctemp;
    19	        myWindow                *owner = win->parent;
    20	        int                     type = win->win_type;
    21	
    22	        panel = (myPanel*)win;
    23	        canvas = (myCanvas*)win;
    24	        frame = (myFrame*)win;
    25	
    26	        while ( (attr = va_arg( ap, int )) != 0 ) {
    27	
    28	                switch ( attr ) {
    29	
    30	                /***************** window attribute *****************/
    31	                case WIN_FONT:
    32	                        win->win_font = va_arg(ap, myPixfont *); 
    33	                        WIN_FONT_modified(modified_flags);
    34	                        break;
    35	                case WIN_CLIENT_DATA:
    36	                        win->win_client_data = va_arg( ap, caddr_t );
    37	                        WIN_CLIENT_DATA_modified(modified_flags);
    38	                        break;
    39	                case WIN_BELOW:
    40	                        win->win_below = va_arg( ap, myWindow* );
    41	                        WIN_BELOW_modified(modified_flags);
    42	                        break;
    43	                case WIN_X:
    44	                        win->win_x = va_arg( ap, int );
    45	                        WIN_X_modified(modified_flags);
    46	                        break;
    47	                case WIN_Y:
    48	                        win->win_y = va_arg( ap, int );
    49	                        WIN_Y_modified(modified_flags);
    50	                        break;
    51	                case WIN_VERTICAL_SCROLLBAR:
    52	                        win->win_vertical_scrollbar = va_arg( ap, Scrollbar );
    53	                        WIN_VERTICAL_SCROLLBAR_modified(modified_flags);
    54	                        break;
    55	                case WIN_LEFT_MARGIN:
    56	                        win->win_left_margin = va_arg( ap, int );
    57	                        WIN_LEFT_MARGIN_modified(modified_flags);
    58	                        break;
    59	                case WIN_TOP_MARGIN:
    60	                        win->win_top_margin = va_arg( ap, int );
    61	                        WIN_TOP_MARGIN_modified(modified_flags);
    62	                        break;
    63	                case WIN_CURSOR:
    64	                        win->win_cursor = va_arg( ap, caddr_t );
    65	                        WIN_CURSOR_modified(modified_flags);
    66	                        break;
    67	
    68	                /******  まだまだ case は続きます  ******/
    69	
    70	                default:
    71	                        fprintf(stderr,"Not supported attr %d in win_attr_set/window.c",attr);
    72	                        va_arg( ap, int );
    73	                        break;
    74	                }
    75	        }
    76	}

関数win_attr_setの可変引数apに適当な定数があると、その定数に従って、その次に整数や文字 列など決まったものが来ます。(printfの引数のように、引数の個数が可変な関数の作り方は、こ こでは特に説明しませんが、絶対にマスターすべきです。)この、可変引数から、指定の型の引数 を参照するにはva_argマクロを使います。そして、その値を適当な変数内部に保管し、WIN_FONT_ modifiedのようなマクロで定数WIN_FONTを記憶する仕掛になっています。つまり、

         window_create( FRAME,
                	WIN_WIDTH,   500,
                	WIN_HEIGHT,  400,
                	FRAME_LABEL, "browser",
                	0 );
のとき、定数WIN_WIDTH,WIN_HEIGHT,FRAME_LABELがあり、それらの値は500,400,"browser"であっ たことを記憶します。そして後で、window_createでどんな値が指定されていたかを調べながら適 当な処理をします。

ここで言う定数(ウィンド属性)は、50個程度もあり、個数が多いため、各定数を1ビットに割 当てています。この定数を示す名前も実はマクロですが、そのマクロ名に_MODIFIEDを付加したも のでビット位置を示し、_modifiedを付加したもので対応ビットをオンにし、さらに先頭にisを付 加したもので、対応ビットのオンオフを取り出すように細工をしています。オンオフを入れる配列 が第3引数のmodified_flagsで、配列のサイズはヘッダーファイル中でMODIFIED_FLAGS_LENで4に なっています。

リスト6−5は、見るからに息苦しいコーディングと思いませんか。ビットを指定するのに、 (0x00000001)のようなビットマスクを延々と書かれるのも嫌です。 属性は4種に大別し、それぞれを分けて書いています。今のところ、とりあえずサポートの必要 あるものに限っているので、どれも32個を越えてはいませんが、もし越えてしまうと変更が必要で す。

ビット単位でオンオフを記憶させたい時には、ビットフィールドを使うのが常識です。構造体の 1要素のビット長を明示することで、簡単に作れます。リスト6−7に、win_attributes型を宣言 しました。これで、面倒で邪魔なマクロを全部きれいに消し去ることができます。何も気にせず、 自然体で書くことができます。

利用する方を書き換えたのがリスト6−8です。マクロでないと大変だと思いこみ、いっぱいマ クロを用意していますが、全然必要ないことが分かるでしょう。

 
リスト6−7 構造体

     1	/********************************************************************************/
     2	/*                          ATTRIBUTES MODIFIED FLAGS                           */
     3	/********************************************************************************/
     4	
     5	typedef struct {
     6	        unsigned int    win_font                : 1;
     7	        unsigned int    win_client_data         : 1;
     8	        unsigned int    win_below               : 1;
     9	        unsigned int    win_x                   : 1;
    10	        unsigned int    win_y                   : 1;
    11	        unsigned int    win_vertical_scrollbar  : 1;
    12	        unsigned int    win_left_margin         : 1;
    13	        unsigned int    win_top_margin          : 1;
    14	        unsigned int    win_cursor              : 1;
    15	
    16	        /*********** まだまだ続きます  *********/
    17	
    18	} win_attributes;

 
リスト6−8 swin_attr_set(構造体利用版)

     1	/********************************************************************************/
     2	/*              set attribute                                                   */
     3	/********************************************************************************/
     4	void
     5	win_attr_set( win, ap, modified_flags )
     6	  myWindow         *win;
     7	  va_list          ap;
     8	  win_attributes   *modified_flags;
     9	{
    10	        myFrame                 *frame;
    11	        myPanel                 *panel;
    12	        myCanvas                *canvas;
    13	        int                     attr;
    14	        va_short                itemp;
    15	        short                   *pointer, *oldpointer;
    16	        myPanel_Item_Choice     *point;
    17	        int                     size, len;
    18	        char                    *ctemp;
    19	        myWindow                *owner = win->parent;
    20	        int                     type = win->win_type;
    21	
    22	        panel = (myPanel*)win;
    23	        canvas = (myCanvas*)win;
    24	        frame = (myFrame*)win;
    25	
    26	        while ( (attr = va_arg( ap, int )) != 0 ) {
    27	
    28	                switch ( attr ) {
    29	
    30	                /***************** window attribute *****************/
    31	                case WIN_FONT:
    32	                        win->win_font = va_arg(ap, myPixfont *); 
    33	                        modified_flags->win_font = 1;
    34	                        break;
    35	                case WIN_CLIENT_DATA:
    36	                        win->win_client_data = va_arg( ap, caddr_t );
    37	                        modified_flags->win_client_data = 1;
    38	                        break;
    39	                case WIN_BELOW:
    40	                        win->win_below = va_arg( ap, myWindow* );
    41	                        modified_flags->win_below = 1;
    42	                        break;
    43	                case WIN_X:
    44	                        win->win_x = va_arg( ap, int );
    45	                        modified_flags->win_x = 1;
    46	                        break;
    47	                case WIN_Y:
    48	                        win->win_y = va_arg( ap, int );
    49	                        modified_flags->win_y = 1;
    50	                        break;
    51	                case WIN_VERTICAL_SCROLLBAR:
    52	                        win->win_vertical_scrollbar = va_arg( ap, Scrollbar );
    53	                        modified_flags->wom_vertical_scrollbar = 1;
    54	                        break;
    55	                case WIN_LEFT_MARGIN:
    56	                        win->win_left_margin = va_arg( ap, int );
    57	                        modified_flags->win_left_margin = 1;
    58	                        break;
    59	                case WIN_TOP_MARGIN:
    60	                        win->win_top_margin = va_arg( ap, int );
    61	                        modified_flags->win_top_margin = 1;
    62	                        break;
    63	                case WIN_CURSOR:
    64	                        win->win_cursor = va_arg( ap, caddr_t );
    65	                        modified_flags->win_cursor = 1;
    66	                        break;
    67	
    68	                /******  まだまだ case は続きます  ******/
    69	
    70	                default:
    71	                        fprintf(stderr,"Not supported attr %d in win_attr_set/window.c",attr);
    72	                        va_arg( ap, int );
    73	                        break;
    74	                }
    75	        }
    76	}

ずいぶん面倒なマクロを定義し、ごたごたと書いていたことが、いかにムダで、不自然だったか 理解できたでしょうか。


Copyright1996 Hirofumi Fujiwara. No reproduction or republication without written permission
『Cプログラミング診断室』目次次(第6章 不慣れ 1行80字)