Reputation: 9363
please read through the following code
#define INT 0
#define CHAR 1
#define FLOAT 2
#define DOUBLE 3
int createKey(int keySize,vector<int> &types, ...){
va_list varlist;
va_start(varlist,types.size());
int intKey;
float floatKey;
char charKey;
double doubleKey;
char *key = (char*)malloc(keySize);
int offset = 0;
for(int i=0;i<types.size();i++){
switch(types[i]){
case INT:
intKey = va_arg(varlist,int);
memcpy(&key[offset],&intKey,sizeof(int));
offset += sizeof(int);
break;
case CHAR:
charKey = va_arg(varlist,char);
memcpy(&key[offset],&charKey,sizeof(char));
offset += sizeof(char);
break;
case FLOAT:
floatKey = va_arg(varlist,float);
memcpy(&key[offset],&floatKey,sizeof(float));
offset += sizeof(float);
break;
case DOUBLE:
doubleKey = va_arg(varlist,double);
memcpy(&key[offset],&doubleKey,sizeof(double));
offset += sizeof(double);
break;
}
va_end(varlist);
}
int testIntKey;
char testCharKey;
float testFloatKey;
double testDoubleKey;
offset = 0;
for(int i=0;i<types.size();i++) {
switch(types[i]){
case INT:
memcpy(&testIntKey,&key[offset],sizeof(int));
cout<<testIntKey<<endl;
offset += sizeof(int);
break;
case CHAR:
memcpy(&testCharKey,&key[offset],sizeof(char));
cout<<testCharKey<<endl;
offset += sizeof(char);
break;
case FLOAT:
memcpy(&testFloatKey,&key[offset],sizeof(float));
cout<<testFloatKey<<endl;
offset += sizeof(float);
break;
case DOUBLE:
memcpy(&testDoubleKey,&key[offset],sizeof(double));
cout<<testDoubleKey<<endl;
offset += sizeof(double);
break;
}
}
}
In the above code, I am trying to create a key that is a combination of one or more of the datatypes(int,char,float,double)...I used ellipses as i donot know the number of arguments that may be passed to createKey(). Now the above code when compiled shows the following warnings..
varargsTest.cpp: In function ‘int createKey(int, std::vector<int, std::allocator<int> >&, ...)’:
varargsTest.cpp:20: warning: second parameter of ‘va_start’ not last named argument
varargsTest.cpp:39: warning: ‘char’ is promoted to ‘int’ when passed through ‘...’
varargsTest.cpp:39: note: (so you should pass ‘int’ not ‘char’ to ‘va_arg’)
varargsTest.cpp:39: note: if this code is reached, the program will abort
varargsTest.cpp:45: warning: ‘float’ is promoted to ‘double’ when passed through ‘...’
varargsTest.cpp:45: note: if this code is reached, the program will abort
and when i run the program with the following ..
int main()
{
vector<int> types;
types.push_back(INT);
types.push_back(CHAR);
types.push_back(INT);
createKey(9,types,85,'s',97);
}
I get Illegal instruction.
How could this problem be solved...Is this the right approach to handle these kind of problems?
Upvotes: 1
Views: 5002
Reputation: 753695
When you call a function with a variable argument list (which is generally a bad idea in C++), then any float
expressions are automatically promoted (converted) to double
, and any char
(any of the three flavours) and short
(two flavours) are promoted to int
. Therefore, as the error message says, you cannot expect va_arg()
to collect a float
or a char
type; you need to collect a double
or int
and coerce the result if necessary.
In general, C++ programmers look unfavourably on variable argument list functions because they are inherently not type-safe and C++ invests a lot of effort into being type-safe.
The 1998 C++ standard essentially incorporates the (1989) C standard specification for <stdarg.h>
verbatim. The 1999 C standard says:
§7.15.1.1 The va_arg macro
Synopsis
#include <stdarg.h> type va_arg(va_list ap, type);
Description
The
va_arg
macro expands to an expression that has the specified type and the value of the next argument in the call. The parameterap
shall have been initialized by theva_start
orva_copy
macro (without an intervening invocation of theva_end
212) macro for the sameap
). Each invocation of theva_arg
macro modifiesap
so that the values of successive arguments are returned in turn. The parametertype
shall be a type name specified such that the type of a pointer to an object that has the specified type can be obtained simply by postfixing a*
totype
. If there is no actual next argument, or iftype
is not compatible with the type of the actual next argument (as promoted according to the default argument promotions), the behavior is undefined, except for the following cases:— one type is a signed integer type, the other type is the corresponding unsigned integer type, and the value is representable in both types;
— one type is pointer to void and the other is a pointer to a character type.
Returns
The first invocation of the
va_arg
macro after that of theva_start
macro returns the value of the argument after that specified byparmN
. Successive invocations return the values of the remaining arguments in succession.212) It is permitted to create a pointer to a va_list and pass that pointer to another function, in which case the original function may make further use of the original list after the other function returns.
The C89 standard is similar but does not support/define va_copy
.
Upvotes: 4