Page 1 of 1

problems with stdarg.h and own printf

Posted: Wed Dec 05, 2007 10:49 am
by FlashBurn
I have the following stdarg.h:

Code: Select all

typedef uint8t *va_list;

#define va_start(ap, v)   ((void) (ap = (va_list) &v + sizeof(v)))
#define va_arg(ap, type) (*((type *)(ap))++)
#define va_end(ap) ((void) (ap = 0))
This is my printf:

Code: Select all

void printf(char *format, ...) {
	va_list argptr;
	char s[34], c, *str;
	int num;
	
	va_start(argptr,format);
	
	while(*format != '\0') {
		if(*format != '%') {
			putchar(*format);
		} else {
			*format++;
			switch(*format) {
			case '%':
				putchar('%');
				break;
			case 'b':
				num= va_arg(argptr,int);
				itoa(s,num,2,PRINTF_SMALL);
				printf(s);
				break;
			case 'c':
				c= va_arg(argptr,char);
				putchar(c);
				break;
			case 's':
				str= va_arg(argptr,char *);
				printf(str);
				break;
			case 'x':
				num= va_arg(argptr,int);
				itoa(s,num,16,PRINTF_SMALL);
				printf(s);
				break;
			case 'X':
				num= va_arg(argptr,int);
				itoa(s,num,16,PRINTF_BIG);
				printf(s);
				break;
			case 'd':
				num= va_arg(argptr,int);
				itoa(s,num,10,PRINTF_SMALL);
				printf(s);
				break;
			default:
				putchar(--*format);
				putchar(++*format);
				break;
			}
		}
		*format++;
	}
	
	va_end(argptr);
}
Whenever I use va_arg I get this error: "lvalue required as increment operand". I have an old kernel which uses the same macros and it does compile, but this code doesn´t. I use gcc 4.2.1 (for both).

Posted: Thu Dec 06, 2007 3:27 am
by Solar
Curious. I'm sure the answer is simple, I just can't find it ad hoc.

Simplified:

Code: Select all

typedef int * va_list;

#define va_start( ap, v ) ((void) (ap = (va_list) &v + sizeof(v)))
#define va_end(ap) ((void) (ap = 0))

#ifdef ORIGINAL
#define va_arg(ap, type) (*((type *)(ap))++)
#else
#define va_arg(ap, type) (*(ap)++)
#endif

int printf( char * format, ... )
{
    va_list argptr;
    va_start( argptr, format );
    int num = va_arg( argptr, int );
    return num;
}

int main()
{
    return printf( "foo", 42 );
}
If compiled with -DORIGINAL, the error appears. If compiled without (i.e., without the cast in va_arg()), it compiles - but returns 20 instead of the expected 42.

Posted: Thu Dec 06, 2007 3:36 am
by FlashBurn
I solved the problem by using other macros:

Code: Select all

#define va_start(ap,v) ap=((uint8t*)&v)+4
#define va_arg(ap,type) (ap+=sizeof(type),*(type*)((void*)ap-sizeof(type)))
#define va_end(ap) ((void)0)

Posted: Thu Dec 06, 2007 4:45 am
by bluecode
A gcc crosscompiler already comes with an implementation of stdarg.h. I would use that instead of your own.

Posted: Thu Dec 06, 2007 2:34 pm
by mystran
Straight from voix library.h:

Code: Select all


// Vararg handling, stdarg.h style, let GCC handle the nastiness..
typedef __builtin_va_list va_list;
#define va_start __builtin_va_start
#define va_end __builtin_va_end
#define va_arg __builtin_va_arg

Posted: Fri Dec 07, 2007 1:39 am
by Solar
Generally speaking, there is no standard-compliant way to do varargs parsing, but every compiler must provide a way to do so. Thus, it's quite OK to rely on the compiler builtins, as mystran showed above.