Search code examples
cavr-gcc

va_arg(argp, float) is crashing


I'm trying to write custom printf function.

void debug_print(const char *fmt, ...)
{
    const char *p;
    va_list argp;
    int i;
    double f;
    char *s;
    char fmtbuf[80];

    va_start(argp, fmt);

    for(p = fmt; *p != '\0'; p++)
    {
        if(*p != '%')
        {
            uart_putchar(*p);
            continue;
        }

        switch(*++p)
        {
            case 'c':
                        ...
            break;

            case 'f':
            f = va_arg(argp, float); // ??????
            s = dtostrf(f, 10, 6, fmtbuf);
            uart_puts(s);
            break;

...
// then in the main part of the program
debug_print("%f", 123.456);

When program comes to f = va_arg(argp, float) it never returns from that line. If I change it to f = va_arg(argp, double) it returns 0.

Tried both on device(ATMega328P) and Atmel Studio 6 simulator, same result.

Sounds like something to do with linker options?

UPDATE:

Now just need to find out why va_arg(argp, double) returns 0.


Solution

  • When you pass a float in a variable argument list, it's implicitly promoted to a double by the compiler. So, you'll have to use va_arg(argp, double) to fetch it from the variable argument list.

    When you do try to fetch the argument as a float, then

    type is not compatible with the type of the actual next argument (as promoted according to the default argument promotions) [and] the behavior is undefined

    (Standard §7.16.1.1, The va_arg macro. Per §6.2.7, float and double are not compatible.)