Improve company productivity with a Business Account.Sign Up

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 260
  • Last Modified:

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
0
ralph78
Asked:
ralph78
1 Solution
 
AxterCommented:
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);
}
0
 
jkrCommented:
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


0
 
nietodCommented:
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?
0
Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
IainHereCommented:
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?
0
 
IainHereCommented:
ARGH! Followed nietod here, but you hadn't posted when I started - apologies.
0
 
nietodCommented:
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.
0
 
ralph78Author Commented:
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
0
 
IainHereCommented:
This is an excellent description of your options:

http://www.cuj.com/articles/2000/0012/0012c/0012c.htm
0
 
nietodCommented:
>> i'll search for an alternative
Well the VA procedures suggested by Axter and others will certainly work.  You woudl have something like

class Vector
{
    public:
       Vector(int Dimensions, ... )
};

However, I still don't recommend it very hardily.   There is nothing to prevent you from doing

Vector V1(3,10); // Error, missing a dimension, may crash.
Vector V2(2,10,20,30); // Error there is a extra dimension, it will probably be missed, but
                                // maybe you wan't it to be a 3D vector.
Vector V2(10);  // Error, forgot to specify the number of dimensions (1) before the size.
Vector V2(1,"I have no clue"); // Error, who knows what size this will be.

None of these errors--and others will be detected by the compiler.  

Now there are alternatives.  If you don't mind breaking this up into multiple operations, you can have one function set the number of dimensions and another function set the size of each dimension.  Like

Vector V;

V.SetNoDimensions(2); // Set to 2 dimesnsions.
V.SetSize(1,20); // Set size of 1st dimension.
V.SetSize(2,30); // Set size of 2nd dimension.
V.SetSize(3.40); // Error.  But at least it has predictable behavior and you can catch it.  (not as nice as a compile-time error though.

Another option is to place the sizing information into a seperate class.   This is an extremely powerful type of solution.   It allows you to delegate properties used during constructio--or other times in the class to sub-classes.  These classes may be written later on or by other programmers.  A very powerful technique.   Just oen example Might be

// The base class.  Defines the 2 interface rfunctiosn the other classes need to provide.
class DimensionConstructorBase
{
public:
    virtual ~DimensionConstructorBase() {} = 0;
    virtual int GetNoDimensions() const = 0;
    virtual int GetDimensionSize(int Dim) const = 0;
};

// Class for a 1D array.
class Dimension1 : public DimensionConstructorBase
{
   int S[1];
public:
     // Constructor specifies the size of dimension.
     Dimension1(int S1) { S[0] = S1; };

     // indicates there is only 1 dimension.
     virtual int GetNoDimensions() const { return 1; }

    // Indicates the size of dimession 1;
    virtual int GetDimensionSize(int Dim) const  { assert(Dim <= 1;  return S[Dim - 1]; }
};


// Class for a 2D array.
class Dimension2 : public DimensionConstructorBase
{
   int S[2];
public:
     // Constructor specifies the size of dimension.
     Dimension2(int S1, int S2) { S[0] = S1; S[1] = S2; };

     // indicates there is only 1 dimension.
     virtual int GetNoDimensions() const { return 1; }

    // Indicates the size of dimession 1;
    virtual int GetDimensionSize(int Dim) const  { assert(Dim <= 1;  return S[Dim  - 1]; }
};

// and so on up to the number of dimesions you expect to support.
// (more dimensions can be added later and templates can be used to help with this.

You could then use it like

Vector V1(Dimension2(10,20));  // Constructor a 2 D array.
Vector V1(Dimension3(10,20,30));  // Constructor a 3 D array.
Vector V1(Dimension2(10,20,30));  // Error is this 2D or 3D?  Cought at compile time.

continues
0
 
nietodCommented:
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.().
0
 
GregToombsCommented:
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
0
 
nietodCommented:
I wish I had thought of that.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

The 14th Annual Expert Award Winners

The results are in! Meet the top members of our 2017 Expert Awards. Congratulations to all who qualified!

Tackle projects and never again get stuck behind a technical roadblock.
Join Now