Link to home
Start Free TrialLog in
Avatar of ralph78
ralph78Flag for France

asked on

parameters...

Hi!
i want to create a function which will use an undefined number of parameters (like printf, execlp...)
but i have no idea about how to do this.
thanks, Ralph
Avatar of Axter
Axter
Flag of United States of America image

If you have VC++, check out the CString implementation as an example.

void FormatV(const TCHAR * lpszFormat, va_list argList)
{
}

void Format(const TCHAR * lpszFormat, ...)
{
     va_list argList;
     va_start(argList, lpszFormat);
     FormatV(lpszFormat, argList);
     va_end(argList);
}
Or this examle from the VC++ docs:

Example

/* VA.C: The program below illustrates passing a variable
 * number of arguments using the following macros:
 *      va_start            va_arg              va_end
 *      va_list             va_dcl (UNIX only)
 */

#include <stdio.h>
#define ANSI            /* Comment out for UNIX version     */
#ifdef ANSI             /* ANSI compatible version          */
#include <stdarg.h>
int average( int first, ... );
#else                   /* UNIX compatible version          */
#include <varargs.h>
int average( va_list );
#endif

void main( void )
{
   /* Call with 3 integers (-1 is used as terminator). */
   printf( "Average is: %d\n", average( 2, 3, 4, -1 ) );

   /* Call with 4 integers. */
   printf( "Average is: %d\n", average( 5, 7, 9, 11, -1 ) );

   /* Call with just -1 terminator. */
   printf( "Average is: %d\n", average( -1 ) );
}

/* Returns the average of a variable list of integers. */
#ifdef ANSI             /* ANSI compatible version    */
int average( int first, ... )
{
   int count = 0, sum = 0, i = first;
   va_list marker;

   va_start( marker, first );     /* Initialize variable arguments. */
   while( i != -1 )
   {
      sum += i;
      count++;
      i = va_arg( marker, int);
   }
   va_end( marker );              /* Reset variable arguments.      */
   return( sum ? (sum / count) : 0 );
}
#else       /* UNIX compatible version must use old-style definition.  */
int average( va_alist )
va_dcl
{
   int i, count, sum;
   va_list marker;

   va_start( marker );            /* Initialize variable arguments. */
   for( sum = count = 0; (i = va_arg( marker, int)) != -1; count++ )
      sum += i;
   va_end( marker );              /* Reset variable arguments.      */
   return( sum ? (sum / count) : 0 );
}
#endif


Avatar of nietod
nietod

You might want to reconsider this.

variable argument (VA) functions are widely considered to be the leading cause of bugs in C programs.  (This has been measured empirically.)   Because VA function do not perform type check on their parameters it is easy to pass invalid data to a VA function and the compiler will not catch it.

C++ provides many great alternatives to VA functions.   Its likely that an alternative will work just as well for you.

What is it that you are hoping to achieve?
ralph78, it might well be the case that this is the best way to do what you're attempting, but consider that C++ offers stringstreams as an alternative to printf for a reason.

The types of the final parameter[s] passed are only checked at run time, and can lead to Hard To Find errors.

printf("%d", "oops");
cout << "no oops";

Maybe you can implement a different interface?
ARGH! Followed nietod here, but you hadn't posted when I started - apologies.
No problem.

Note that its very likely that this does not concern outputting the information.   I think ralph78 only used printf() asn an example of a function that takes an unspecified number of parameters, not necessarily one that performs the desired operation.   However, the C++ stream objects are an example of one alternative solution to VA functions.
Avatar of ralph78

ASKER

ok, thank u all!
i'll search for an alternative
(i'm writing a VECTOR class (i can't use STL), and it's about vectors of undefined dimensions.
i need a "Set" method, which will set the attributes of a VECTOR.
for instance:

VECTOR v(4);    //4d vector
v.Set(4,1,2,3,4); //1st param is the number of parameters
This is an excellent description of your options:

http://www.cuj.com/articles/2000/0012/0012c/0012c.htm
ASKER CERTIFIED SOLUTION
Avatar of nietod
nietod

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
You could also do this with a single dimension class (unlike the version above that uses 1 class for each number of dimesions you want to support).  To do this the class would record the number of dimesions on a dynamic array.  Like

class Dimesion
{
    vector<int> S;
public:
     // Constructor takes first dimension.
     Dimension(int S1) { S.push_back(S1); };
     // Add an additional dimension.
     // Returns a reference to itself for "chaining"--look at how it is used.
     // A shorter name is probably better.
     Dimension & AddDimension(int Sn) { S.push_back(Sn);   return *this;  };
     // Get the number of dimesions.
     int GetNoDimensions() { return S.size(); };
      // Get the size of a particular dimension.
     int GetDimension(int i) {  return S[i]; };
}


You would use this like

Vector V( Dimension(10)); // Create a 1D vector. (10)
Vector V( Dimension(10).AddDimension(20) );  // Create a 2D vector.  (10 X 20).
Vector V( Dimension(10).AddDimension(20).AddDimension(30 );  // Create a 3D vector.  (10 X 20 X 30).

You could also give the class  a few different constructors, so the common dimesions (1, 2, and 3) could all be handled without chaining to AddDimension.().
I'd suggest writing a linked list class describing the dimensions of the vector. For something like your Set function, then, all you'd have to do is pass a reference to the class.

-Greg
I wish I had thought of that.