第10回 続・C99規格についての説明と検証

岸 哲夫

 前回に引き続き,C99規格についての説明と検証について解説する.今回は, ・追加された関数やマクロについて ・新規に追加された標準ライブラリについて ・C99規格対応に関するGNU Cのバージョンごとの進捗 に関して,説明と検証を行う. (筆者)

space

 今回も,前回に引き続き「ISO/IEC 9899 : 1999 - Programming Language C」(略称:C99)規格について説明と検証をします.

追加された関数やマクロについて

● マクロDECIMAL_DIG

 これについては,完全にフィックスされていないのが現状です.GCC3.2から導入されています.次のように定義されています.

  # define DECIMAL_DIG 21

● マクロFLT_EVAL_METHOD

 GCC3.2から導入されています.以下のように定義されています.

  # define FLT_EVAL_METHOD 2

 実際にこの値が意味することは,以下のとおりです.

・FLT_EVAL_METHODの値が−1:浮動小数点計算の方式は不定である
・FLT_EVAL_METHODの値が0:型を保持して計算する
・FLT_EVAL_METHODの値が1:floatはDoubleに型拡張される.double,long doubleはそのまま
・FLT_EVAL_METHODの値が2:float,doubleはlong doubleに型拡張される.long doubleはそのまま

 つまり,GCC3.2では「float,doubleはlong doubleに型拡張され,long doubleはそのまま」という計算方式になります.これからGCC3.2の導入を考えている方は,心にとどめておいてください.

● マクロva_copy

 リスト1に使用例を,リスト2にマクロ展開リストの一部を,リスト3に生成されたアセンブラコードを示します.以下は実行結果です.

〔リスト1〕va_copyの例test126.c)
#include <stdarg.h>
/*
 *va_copyについて
 */
#include <stdio.h>
void func(int num, ...);
main()
{
        func(4,"aa","bb","cc","dd");
        func(6,"aa-","bb-","cc-","dd-","ee-","ff-");
}
void func(int num, ...)
{
        va_list ap;
        va_list dup_ap;
        char    *str;
        int     ix;
        va_start(ap, num);
    __va_copy(dup_ap,ap);
        for(ix=0;ix<num;ix++)
        {
        printf("apの%d番目の引き数は%s\n",ix+1,va_arg(ap, char *));
    }
        printf("\n");
        for(ix=0;ix<num;ix++)
        {
        printf("dup_apの%d番目の引き数は%s\n",ix+1,va_arg(dup_ap, char *));
    }
        printf("\n");
        va_end(ap);
        va_end(dup_ap);
}

〔リスト2〕マクロ展開リストの一部test126.src)
void func(int num, ...)
{
        va_list ap;
        va_list dup_ap;
        char    *str;
        int     ix;
        ( ap  = ((__gnuc_va_list) __builtin_next_arg (  num ))) ;
    ( dup_ap ) = ( ap ) ;
        for(ix=0;ix<num;ix++)
        {
        printf("apの%d番目の引き数は%s\n",ix+1,( ap  = (__gnuc_va_list) ((char *) ( ap ) +
	(((sizeof (   char *  ) + sizeof (int) - 1)  / sizeof (int)) * sizeof (int)) ), 
	*((  char *  *) (void *) ((char *) ( ap )    (((sizeof (   char *  ) + sizeof (int) - 1) / 
	sizeof (int)) * sizeof (int)) ))) );
    }
        printf("\n");
        for(ix=0;ix<num;ix++)
        {
        printf("dup_apの%d番目の引き数は%s\n",ix+1,( dup_ap  = (__gnuc_va_list)
	((char *) ( dup_ap ) + (((sizeof (   char *  ) +  sizeof (int) - 1) / sizeof (int)) * sizeof
	(int)) ),  *((  char *  *) (void *) ((char *) ( dup_ap ) -  (((sizeof (   char *  ) 
	+ sizeof (int) - 1) / sizeof (int)) * sizeof (int)) ))) );
    }
        printf("\n");
        ((void)0) ;
        ((void)0) ;
}

〔リスト3〕生成されたアセンブラコードtest126.s)
        .file   "test126.c"
        .version        "01.01"
gcc2_compiled.:
.section        .rodata
.LC0:
        .string "dd"
.LC1:
        .string "cc"
.LC2:
        .string "bb"
.LC3:
        .string "aa"
.LC4:
        .string "ff-"
.LC5:
        .string "ee-"
.LC6:
        .string "dd-"
.LC7:
        .string "cc-"
.LC8:
        .string "bb-"
.LC9:
        .string "aa-"
.text
        .align 4
.globl main
        .type    main,@function
main:
        pushl %ebp
        movl %esp,%ebp
        subl $8,%esp
        addl $-12,%esp
        pushl $.LC0
        pushl $.LC1
        pushl $.LC2
        pushl $.LC3
        pushl $4
        call func
        addl $32,%esp
        addl $-4,%esp
        pushl $.LC4
        pushl $.LC5
        pushl $.LC6
        pushl $.LC7
        pushl $.LC8
        pushl $.LC9
        pushl $6
        call func
        addl $32,%esp
.L2:
        movl %ebp,%esp
        popl %ebp
        ret
.Lfe1:
        .size    main,.Lfe1-main
.section        .rodata
.LC10:
        .string "ap\244\316%d\310\326\314\334
\244\316\260\372\277\364\244\317%s\n"
.LC11:
        .string "\n"
.LC12:
        .string "dup_ap\244\316%d\310\326\314
\334\244\316\260\372\277\364\244\317%s\n"
.text
        .align 4
.globl func
        .type    func,@function
func:
        pushl %ebp
        movl %esp,%ebp
        subl $24,%esp
        leal 12(%ebp),%eax
        movl %eax,-4(%ebp)
        movl -4(%ebp),%eax
        movl %eax,-8(%ebp)
        movl $0,-16(%ebp)
        .p2align 4,,7
.L4:
        movl -16(%ebp),%eax
        cmpl 8(%ebp),%eax
        jl .L7
        jmp .L5
        .p2align 4,,7
.L7:
        addl $-4,%esp
        addl $4,-4(%ebp)
        movl -4(%ebp),%eax
        addl $-4,%eax
        movl (%eax),%edx
        pushl %edx
        movl -16(%ebp),%eax
        incl %eax
        pushl %eax
        pushl $.LC10
        call printf
        addl $16,%esp
.L6:
        incl -16(%ebp)
        jmp .L4
        .p2align 4,,7
.L5:
        addl $-12,%esp
        pushl $.LC11
        call printf
        addl $16,%esp
        movl $0,-16(%ebp)
        .p2align 4,,7
.L8:
        movl -16(%ebp),%eax
        cmpl 8(%ebp),%eax
        jl .L11
        jmp .L9
        .p2align 4,,7
.L11:
        addl $-4,%esp
        addl $4,-8(%ebp)
        movl -8(%ebp),%eax
        addl $-4,%eax
        movl (%eax),%edx
        pushl %edx
        movl -16(%ebp),%eax
        incl %eax
        pushl %eax
        pushl $.LC12
        call printf
        addl $16,%esp
.L10:
        incl -16(%ebp)
        jmp .L8
        .p2align 4,,7
.L9:
        addl $-12,%esp
        pushl $.LC11
        call printf
        addl $16,%esp
.L3:
        movl %ebp,%esp
        popl %ebp
        ret
.Lfe2:
        .size    func,.Lfe2-func
        .ident  "GCC: (GNU) 2.95.3
        20010315 (release)"
	

  $ ./test126
  apの1番目の引き数はaa
  apの2番目の引き数はbb
  apの3番目の引き数はcc
  apの4番目の引き数はdd

  dup_apの1番目の引き数はaa
  dup_apの2番目の引き数はbb
  dup_apの3番目の引き数はcc
  dup_apの4番目の引き数はdd

  apの1番目の引き数はaa-
  apの2番目の引き数はbb-
  apの3番目の引き数はcc-
  apの4番目の引き数はdd-
  apの5番目の引き数はee-
  apの6番目の引き数はff-

  dup_apの1番目の引き数はaa-
  dup_apの2番目の引き数はbb-
  dup_apの3番目の引き数はcc-
  dup_apの4番目の引き数はdd-
  dup_apの5番目の引き数はee-
  dup_apの6番目の引き数はff-

 このようにva_startや__va_copyはマクロになっています.va_endは,ここで見るかぎり不要に見えますが,処理によっては必要になるはずなので,va_startや__va_copyごとに必ず定義してください.

 アセンブラソースを見てもわかるように,__va_copyマクロはアドレスをコピーするだけではなく,領域を確保してコピーを行っています.よって,元のデータを破壊してもコピー先は保持されます.


NEW記事内インデックス    連載インデックスはこちら   Interfaceのトップ
◆追加された関数やマクロについて
math.hのマクロ
stdio.hに追加されたいくつかの関数/stdlibに追加されたいくつかの関数
C99規格で新規に追加された標準ライブラリ

Copyright 2003 岸 哲夫

Copyright 1997-2017 CQ Publishing Co.,Ltd.