Skip navigation

This is some code that stores the values passed to a variadic function in a stack-like <vector>.

Each va_list argument that got passed in the place of … will be saved as a va_item in the va_stack vector.

It preserves the original datatype in va_item.datatype as just a character string. The actual data is stored with a generic pointer (type void*) in va_item.data.


//////////////////////////////////////////
//                                      //
// VARIABLE ARGUMENT LISTS ## revisited //
//                                      //
// You found this at bobobobo's weblog, //
// https://bobobobo.wordpress.com        //
//                                      //
// Creation date:  June 4/08            //
// Last modified:  June 4/08            //
//                                      //
//////////////////////////////////////////
//
// This code file is the result of comments
// by Ran.

// It is supposed to be some code that can
// save off the values that are passed to
// a variadic function ( a variadic function
// is just a function that accepts the ...
// variable number of arguments).

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>

#include <vector>
using namespace std;


// Some defs.
#define  CHAR           "char"
#define  INT            "int"
#define  FLOAT          "float"
#define  DOUBLE         "double"
#define  STRING         "char *"
#define  BOBBLEDEBOOP   "BobbledeBoop"


// Some protos.
void saveThem_using_va_arg( char * argsfmt, ... );
int getSizeOfDataType( char * datatype );
char * getDatatypeString( char datatype );


// some object, for testing purposes
struct BobbledeBoop
{
    int a, b, c, d;
    float x, y, z, w;

    void print()
    {
        printf("bobble bobble bobble %d %d %d %d %.2f %.2f %.2f %.2f\n",
                a,b,c,d,x,y,z,w );
    }
};

struct va_item
{
    const static int MAX_TYPE_NAME_LENGTH = 32;
    // 32 chars max length for datatype
    
    char datatype[ MAX_TYPE_NAME_LENGTH ];
    
    void * data;    // generic pointer.
    // this pointer will actually hold
    // the data itself.
};




// typedefs
typedef   vector<va_item *>               va_stack ;
typedef   vector<va_item *>::iterator     va_stack_iterator ;




//////////////////
// globs
// declare a global va_stack
va_stack stack;



int main()
{
    // test the code.

    saveThem_using_va_arg( "%d %s %t %c", 20, "a string", 247.5546, 'x' );
    saveThem_using_va_arg( "%d %d %t %c", 20, 90, 247.5546, 'x' );
    saveThem_using_va_arg( "%s %s %d %c",
        "some text data",
        "and then some more text data",
        30000,
        'b' );
   
    BobbledeBoop bbd;
    bbd.a = 110;
    bbd.b = 220;
    bbd.c = 330;
    bbd.d = 440;
    bbd.x = 110.1;
    bbd.y = 220.2;
    bbd.z = 330.3;
    bbd.w = 440.4;

    saveThem_using_va_arg( "%B", bbd );

    bbd.x = 20000;
    saveThem_using_va_arg( "%B", bbd );

    saveThem_using_va_arg( "%c %B %d", 'r', bbd, 2000 );
    saveThem_using_va_arg( "%c %t %d", 'r', 299.944, 2000 );

    /////////
    // print.
    for( va_stack_iterator it = stack.begin();
         it != stack.end();
         ++it )
    {
        char * datatype = (*it)->datatype;
        printf( "datatype:  %s\n", datatype );

        // its necessary to reinterpret the void* pointer
        // before attempting to dereference it.
        if( strcmp( datatype, CHAR ) == 0 )
        {
            // char data.
            printf("data:  %c\n", *(reinterpret_cast<char *>( (*it)->data ) ));
        }        
        else if( strcmp( datatype, INT ) == 0 )
        {
            printf("data:  %d\n", *(reinterpret_cast<int *>( (*it)->data ) ));
        }
        else if( strcmp( datatype, FLOAT ) == 0 )
        {
            printf("data:  %f\n", *(reinterpret_cast<float *>( (*it)->data ) ));
        }
        else if( strcmp( datatype, DOUBLE ) == 0 )
        {
            printf("data:  %f\n", *(reinterpret_cast<double *>( (*it)->data ) ));
        }
        else if( strcmp( datatype, STRING ) == 0 )
        {
            printf("data:  %s\n", (reinterpret_cast<char *>( (*it)->data ) ));
        }
        else if( strcmp( datatype, BOBBLEDEBOOP ) == 0 ) // BobbledyBoop object
        {
            printf("data:  " );
            (reinterpret_cast<BobbledeBoop *>( (*it)->data ) )->print();

        }
        printf("\n");
    }

    return 0;
}


/// Accepts a format string
/// and a va_list and saves
/// them to the global va_stack 'stack'
void saveThem_using_va_arg( char * argsfmt, ... )
{
    va_list listPointer;

    va_start( listPointer, argsfmt );

    // fetch type from fmt string
    char * next = strchr( argsfmt, '%' );

    do // while there's another %...
    {
        va_item * item = (va_item*)malloc(sizeof(va_item));   // declare a new va_item.

        // get the next char, which tells
        // what kind of data it is.
        char ctype = next[1];
        
        char * datatype = getDatatypeString( ctype );

        strcpy( item->datatype, datatype );  //save datatype in the va_item.

        int datalength = getSizeOfDataType( datatype );
        if( datalength == 0 ) {
            printf("FATAL ERROR: I didn't know datatype %s\n", datatype);
            return;
        }

        //save undying ref to data in va_item.
        item->data = (void*)malloc( datalength );


        // retrieve and copy the data.
        if( strcmp( datatype, CHAR ) == 0 )
        {
            char data = va_arg( listPointer, char );
            memcpy( item->data, &data, datalength );
        }        
        else if( strcmp( datatype, INT ) == 0 )
        {
            int data = va_arg( listPointer, int );
            memcpy( item->data, &data, datalength );
        }
        else if( strcmp( datatype, FLOAT ) == 0 )
        {
            float data = va_arg( listPointer, float );
            memcpy( item->data, &data, datalength );
        }
        else if( strcmp( datatype, DOUBLE ) == 0 )
        {
            double data = va_arg( listPointer, double );
            memcpy( item->data, &data, datalength );
        }
        else if( strcmp( datatype, STRING ) == 0 )
        {
            char * data = va_arg( listPointer, char * );

            datalength = strlen(data);

            // special case for string.  longer data region.
            // reallocate.
            free( item->data );

            item->data = (void*)malloc( datalength );

            strcpy( (char*)item->data, data );
        }
        else if( strcmp( datatype, BOBBLEDEBOOP ) == 0 ) // BobbledyBoop object
        {
            BobbledeBoop data = va_arg( listPointer, BobbledeBoop );
            memcpy( item->data, &data, datalength );
        }
        else
        {
            printf("I didn't know the type %s.\n", datatype );
            return; // type not known, so . . . 
        }

        
        // push that new item onto the stack.
        stack.push_back( item );

        
    } while( next = strchr( next+1, '%' ) ); // next item


    va_end( listPointer );

}


int getSizeOfDataType( char * datatype )
{
    if( strcmp( datatype, CHAR ) == 0 )
    {
        return sizeof( char );
    }        
    else if( strcmp( datatype, INT ) == 0 )
    {
        return sizeof( int );
    }
    else if( strcmp( datatype, FLOAT ) == 0 )
    {
        return sizeof( float );
    }
    else if( strcmp( datatype, DOUBLE ) == 0 )
    {
        return sizeof( double );
    }
    else if( strcmp( datatype, STRING ) == 0 )
    {
        return sizeof( char * );
    }
    else if( strcmp( datatype, BOBBLEDEBOOP ) == 0 ) // BobbledyBoop object
    {
        return sizeof( BobbledeBoop ); // return the size of the BobbledyBoop object
    }
    else
    {
        printf("I didn't know the type %s.\n", datatype );
        return 0; // type not known, so . . . 
    }
}

char * getDatatypeString( char datatype )
{
    switch( datatype )
    {
    case 'c':
        return CHAR;
        break;
    case 'd':
        return INT;
        break;
    case 'f':
        return FLOAT;
        break;
    case 't':
        return DOUBLE;
        break;
    case 's':
        return STRING;
        break;
    case 'B':
        return BOBBLEDEBOOP;
        break;
    default:
        printf("I didn't know the type %c.\n", datatype );
        return 0;
    }
}
/* 
     ____   __   __      __   __  ___
    / _  \ /  / /  /    /  /  \ \/  /
   / _/ / /  / /  /    /  /    \   /
  / _/ \ /  / /  /__  /  /__   /  /
 /_____//__/ /______//______/ /__/

*/

code on esnips!

Advertisements

One Comment

    • Anonymous
    • Posted August 22, 2009 at 6:59 pm
    • Permalink

    Hi;

    You should change the function signature, to const char* and the return value of getDatatypeString to const char*. This will make compiler happy and no deprecated compiler warnings will pop up


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 )

Google+ photo

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

Connecting to %s

%d bloggers like this: