Simple safe printf snippet

A little prototype for an idea I had to use some C++11 features to make printf a bit more safe.


#include <initializer_list>
#include <stdio.h>

struct val_t {

    enum type_t { 

        e_int, 
        e_float, 
        e_cstr 
    } type_;

    union {

        int          int_;
        float        float_;
        const char * cstr_;
    };

    val_t( int v )          : type_( e_int   ), int_  ( v ) {}
    val_t( float v )        : type_( e_float ), float_( v ) {}
    val_t( const char * v ) : type_( e_cstr  ), cstr_ ( v ) {}
};

bool print( const char * fmt, std::initializer_list<val_t> vargs ) {

    // itterate over the strings
    for ( ; *fmt;fmt++ ) {
        // check for format specifier
        if ( *fmt == '%' ) {
            // argument index
            int index = fmt[1] - '0';
            if (index < 0 || index >= int(vargs.size()))
                return false;
            // access argument
            const val_t & v = vargs.begin()[index];
            switch (v.type_) {
            case (val_t::e_int  ): printf("%d", v.int_   ); break;
            case (val_t::e_float): printf("%f", v.float_ ); break;
            case (val_t::e_cstr ): printf("%s", v.cstr_  ); break;
            default:
                return false;
            }
            // skip argument index
            fmt++;
        }
        else {
            // output character
            putchar(*fmt);
        }
    }
    return true;
}

int main( void ) {
    print( "%0 and %1, %0, %2", { 3, 0.1f, "hello world" } );
    getchar();
    return 0;
}

The output is:

3 and 0.100000, 3, hello world

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s