2

私の NC30 M16C コンパイラ バージョン 5 には、以前のプログラマが使用した次のマクロがありました。このマクロは、「printf()」、「sprintf()」などの関数で使用します。

typedef unsigned char * va_list;
#define va_start( args, first ) args = (va_list) ( (unsigned short) &first + sizeof( first ) )
#define va_arg( args, type ) *( (type *) args )++
#define va_end( args )

このコードを NC30 M16C コンパイラ バージョン 6 でコンパイルすると、「無効な左辺値」というエラーが表示されます。エラー メッセージ全体の一部を次に示します。

clib.c(253) :  C2700 (E) invalid lvalue
===>    unum = va_arg( args, unsigned int );
clib.c(293) :  C2700 (E) invalid lvalue
===>    fch = va_arg( args, far char * );
clib.c(299) :  C2700 (E) invalid lvalue
===>    nch = va_arg( args, char * );
clib.c(305) :  C2700 (E) invalid lvalue
===>    unum = va_arg( args, unsigned int );
clib.c(323) :  C2700 (E) invalid lvalue
===>    ulong = va_arg( args, unsigned long );
clib.c(341) :  C2700 (E) invalid lvalue
===>    llong = va_arg( args, unsigned long long );
clib.c(359) :  C2700 (E) invalid lvalue
===>    ulong = va_arg( args, unsigned long );
clib.c(377) :  C2700 (E) invalid lvalue
===>    unum = va_arg( args, unsigned short );
clib.c(382) :  C2700 (E) invalid lvalue
===>    ft = va_arg( args, float );
clib.c(519) :  C2694 (E) unknown variable source
===>    *source++ = zeropad ? '0' : ' ';
clib.c(527) :  C2694 (E) unknown variable source
===>    *source++ = '%';
clib.c(532) :  C2700 (E) invalid lvalue
===>    snum = va_arg( args, signed int );
clib.c(550) :  C2694 (E) unknown variable source
===>        *source++ = *tempptr;
clib.c(556) :  C2700 (E) invalid lvalue
===>    fch = va_arg( args, far char * );
clib.c(558) :  C2694 (E) unknown variable source
===>        *source++ = *fch++;
clib.c(564) :  C2700 (E) invalid lvalue
===>    nch = va_arg( args, char * );
clib.c(566) :  C2694 (E) unknown variable source
===>        *source++ = *nch++;
clib.c(572) :  C2700 (E) invalid lvalue
===>    unum = va_arg( args, unsigned int );

これは、これらのマイクロを使用した関数の 1 つです。この関数は「printf」と同じ関数ですが、zwPrintf() という名前が付けられています。

int zwPrintf( far char * format, ... ) {
    zwVAList args;
    unsigned int unum;
    unsigned char temp[ FIELD_BUFF_SIZE + 1 ];      /* for formatting numbers (max length for long decimal) */
    unsigned char * tempptr;
    int zeropad, minfield, counter;
    far char * fch;
    char * nch;
    unsigned long ulong;
    int negative;
    float ft, mantissa;
    unsigned long long llong;
    //unsigned char mychar;
    //unsigned char *mychar_p;
    //unsigned int *mytest_p;

    va_start( args, format );

    while( *format ) {
        if( *format == '%' ) {
            format++;
            zeropad = 0;
            minfield = 0;
            negative = 0;
            if( *format == '0' )
                zeropad = 1;            /* we want zero padding to field width */
            while( *format >= '0' && *format <= '9' ) {
                /* we are specifying field width */
                minfield *= 10;
                minfield += *format - '0';
                format++;
            }
            if( minfield > FIELD_BUFF_SIZE ) {      /* we want a field width greater than our field buffer, pad misc */
                for( counter = 0; counter < minfield - FIELD_BUFF_SIZE; counter++ )
                    zwPutc( (unsigned char) ( zeropad ? '0' : ' ' ) );
                minfield = FIELD_BUFF_SIZE;
            }
            switch( *format ) {
                case '%':   /* literal % */
                    zwPutc( '%' );
                break;

                case 'd':   /* signed decimal output */
                    unum = va_arg( args, unsigned int );        /* pull unsigned, and do math ourselves (to avoid confusion) */

                    //mychar='a';
                    //mychar_p = &mychar;
                    //mytest_p = ((unsigned int*)mychar_p);
                    //mytest_p++;
                    //unum = *mytest_p;
                    //unum = (*((unsigned int*)args))++;
                    //unum = (*((unsigned int*)args))++;

                    /* convert to decimal (backward) */
                    if( unum >= 0x8000 ) {      /* number is -'ve */
                        negative = 1;
                        unum = ~unum + 1;           /* make number +'ve */
                    }

                    tempptr = &temp[ FIELD_BUFF_SIZE ];
                    counter = 0;
                    do {
                        if( unum )
                            *tempptr-- = ( unum % 10 ) + '0';
                        else {
                            if( negative && ( zeropad == 0 ) ) {
                                *tempptr-- = '-';
                                negative = 0;
                            }
                            else
                                *tempptr-- = ( zeropad || counter == 0 ) ? '0' : ' ';
                        }
                        unum /= 10;
                        counter++;
                    } while( unum || counter < minfield );
                    /* output the string */
                    if( negative )
                        zwPutc( '-' );
                    for( tempptr++; tempptr <= &temp[ FIELD_BUFF_SIZE ]; tempptr++ )
                        zwPutc( *tempptr );
                break;

                case 's':   /* far char * */
                    fch = va_arg( args, far char * );
                    while( *fch )
                        zwPutc( *fch++ );
                break;

                case 'S':   /* near char * (extension) */
                    nch = va_arg( args, char * );
                    while( *nch )
                        zwPutc( *nch++ );
                break;

                case 'x':   /* hexadecimal */
                    unum = va_arg( args, unsigned int );
                    /* convert to hexadecimal (backward) */
                    tempptr = &temp[ FIELD_BUFF_SIZE ];
                    counter = 0;
                    do {
                        if( unum )
                            *tempptr-- = zwHexToAsc( (unsigned char) unum & 0x0F );
                        else
                            *tempptr-- = ( zeropad || counter == 0 ) ? '0' : ' ';
                        unum >>= 4;
                        counter++;
                    } while( unum || counter < minfield );
                    /* output the string */
                    for( tempptr++; tempptr <= &temp[ FIELD_BUFF_SIZE ]; tempptr++ )
                        zwPutc( *tempptr );
                break;

                case 'i':   /* unsigned long int decimal (extension) */
                    ulong = va_arg( args, unsigned long );
                    /* convert to decimal (backward) */
                    tempptr = &temp[ FIELD_BUFF_SIZE ];
                    counter = 0;
                    do {
                        if( ulong )
                            *tempptr-- = (unsigned char)( ulong % 10 ) + '0';
                        else
                            *tempptr-- = ( zeropad || counter == 0 ) ? '0' : ' ';
                        ulong /= 10;
                        counter++;
                    } while( ulong || counter < minfield );
                    /* output the string */
                    for( tempptr++; tempptr <= &temp[ FIELD_BUFF_SIZE ]; tempptr++ )
                        zwPutc( *tempptr );
                break;

                case 'L':   /* unsigned long long decimal (extension) */
                    llong = va_arg( args, unsigned long long );
                    /* convert to decimal (backward) */
                    tempptr = &temp[ FIELD_BUFF_SIZE ];
                    counter = 0;
                    do {
                        if( llong )
                            *tempptr-- = (unsigned char)( llong % 10 ) + '0';
                        else
                            *tempptr-- = ( zeropad || counter == 0 ) ? '0' : ' ';
                        llong /= 10;
                        counter++;
                    } while( llong || counter < minfield );
                    /* output the string */
                    for( tempptr++; tempptr <= &temp[ FIELD_BUFF_SIZE ]; tempptr++ )
                        zwPutc( *tempptr );
                break;

                case 'h':   /* unsigned long int hexadecimal (extension) */
                    ulong = va_arg( args, unsigned long );
                    /* convert to hexadecimal (backward) */
                    tempptr = &temp[ FIELD_BUFF_SIZE ];
                    counter = 0;
                    do {
                        if( ulong )
                            *tempptr-- = zwHexToAsc( ( (unsigned char) ulong ) & 0x0F );
                        else
                            *tempptr-- = ( zeropad || counter == 0 ) ? '0' : ' ';
                        ulong >>= 4;
                        counter++;
                    } while( ulong || counter < minfield );
                    /* output the string */
                    for( tempptr++; tempptr <= &temp[ FIELD_BUFF_SIZE ]; tempptr++ )
                        zwPutc( *tempptr );
                break;

                case 'c':
                    unum = va_arg( args, unsigned short );
                    zwPutc( (char) unum );
                break;

                case 'f':
                    ft = va_arg( args, float );
#if 0
                    /* convert to decimal (backward) */
                    if( ft < 0 ) {      /* number is -'ve */
                        negative = 1;
                        ft = -ft;
                    }

                    tempptr = &temp[ FIELD_BUFF_SIZE ];
                    counter = 0;

                    /* split float to integer and mantissa part */
                    ulong = ft / 1;
                    mantissa = ft - ( float )ulong;

                    /* get integer part */
                    do {
                        if( ulong ){
                            *tempptr-- = (unsigned char)( ulong % 10 ) + '0';
                        }
                        else {
                            *tempptr-- = ( zeropad || counter == 0 ) ? '0' : ' ';
                        }
                        ulong /= 10;
                        counter++;
                    } while( ulong || counter < minfield );

                    if ( negative ) {
                        temp[ 0 ] = '-';
                        zwMemcpy( &temp[ 1 ], &temp[ FIELD_BUFF_SIZE - counter ], counter );        //change to right position
                        counter++;
                    }
                    else
                        zwMemcpy( &temp[ 0 ], &temp[ FIELD_BUFF_SIZE - counter ], counter );

                    temp[ counter++ ] = '.';                        

                    /* get mantissa part */
                    tempptr = &temp[ counter ];
                    do {
                        unum = ( mantissa * 10 ) / 1;
                        if( unum ){
                            *tempptr++ = (unsigned char)( unum ) + '0';     
                        }
                        else {
                            *tempptr++ = '0';   
                        }

                        mantissa = ( float ) ( mantissa * 10.0 - ( float )unum ) * 10.0;                        
                        counter++;
                    } while( mantissa > 0 || counter < minfield );


                    for( unum = 0; unum < counter; unum++ )
                        zwPutc( temp[ unum ] );

                    /* convert to decimal (backward) */
                    if( ft < 0 ) {      /* number is -'ve */
                        negative = 1;
                        ft = -ft;
                    }

                    tempptr = &temp[ FIELD_BUFF_SIZE ];
                    counter = 0;
                    do {
                        if( ft >= 1.0 ){
                            *tempptr-- = ( ft % 10.0 ) + '0';
//                          *tempptr-- = ( ft * 10 - ( ( ft * 100 ) / 10 ) ) + '0';
                        }
                        else {
                            if( negative && ( zeropad == 0 ) ) {
                                *tempptr-- = '-';
                                negative = 0;
                            }
                            else
                                *tempptr-- = ( zeropad || counter == 0 ) ? '0' : ' ';
                        }
                        ft /= 10;
                        counter++;
                    } while( ft >= 1.0 || counter < minfield );

                    /* output the string */
                    if( negative )
                        zwPutc( '-' );

                    for( tempptr++; tempptr <= &temp[ FIELD_BUFF_SIZE ]; tempptr++ )
                        zwPutc( *tempptr );
#endif
                break;

                case 0:     /* end of string (malformed string anyway) */
                    va_end( args );
                    return -1;      /* error */
                break;
            }
        }
        else
            zwPutc( *format );

        format++;
    }

    va_end( args );

    return -1;
}

この問題を修正するにはどうすればよいですか。

前もって感謝します。

4

1 に答える 1

0

置き換えてみてください:

#define va_arg( args, type ) *( (type *) args )++

#define va_arg( args, type ) *( (type *) args ), args += sizeof (type)

説明:

次の式が原因で、コンパイル エラーが発生します。

((type *) args )++

C では無効です: キャストの結果は左辺値ではなく、後置++演算子はそのオペランドが左辺値であることを要求します。多くのコンパイラはこの制約に緩いですが、明らかにそうではありません (または、新しいバージョンはより厳密です)。

また、提案された回避策は、次のような単純な代入式を使用するプログラムで機能するはずであることに注意してください。

unum = va_arg( args, unsigned int );

=コンマ演算子よりも優先順位が高いためです。

編集

別の(おそらくさらに良い)解決策:この解決策を使用して、キャストの結果が左辺値ではないという事実を回避できるはずです:

#define va_arg( args, type ) *( *(type **) &args )++
于 2012-08-02T23:16:08.270 に答える