请仔细阅读以下代码
#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;
}
}
}
在上面的代码中,我试图创建一个键,它是一个或多个数据类型的组合(int,char,float,double)...我使用省略号,因为我不知道参数的数量可以传递给createKey()。现在编译时的上述代码显示以下警告..
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
当我使用以下程序运行程序时..
int main()
{
vector<int> types;
types.push_back(INT);
types.push_back(CHAR);
types.push_back(INT);
createKey(9,types,85,'s',97);
}
我得到Illegal instruction.
如何解决这个问题......这是处理这类问题的正确方法吗?
答案 0 :(得分:3)
当您使用可变参数列表调用函数时(在C ++中通常是一个坏主意),任何float
表达式都会自动提升(转换)为double
,并且任何{{1 (三种风格中的任何一种)和char
(两种风格)被提升为short
。因此,正如错误消息所示,您不能指望int
收集va_arg()
或float
类型;您需要收集char
或double
并在必要时强制执行结果。
一般来说,C ++程序员看起来不利于变量参数列表函数,因为它们本质上不是类型安全的,而且C ++投入了大量精力来保证类型安全。
1998 C ++标准基本上包含int
逐字的(1989)C标准规范。 1999 C标准说:
§7.15.1.1va_arg宏
概要
<stdarg.h>
描述
#include <stdarg.h> type va_arg(va_list ap, type);
宏扩展为具有指定类型和值的表达式 通话中的下一个参数。参数va_arg
应该由。初始化ap
或va_start
宏(没有干预va_copy
212的调用) 同一个va_end
的宏。ap
宏的每次调用都会修改va_arg
以便{。}} 连续参数的值依次返回。参数ap
应为类型 指定的名称,使得指向具有指定类型的对象的指针的类型可以 只需将type
后缀为*
即可获得。如果没有实际的下一个参数,或者如果type
与实际的下一个参数的类型不兼容(正如提升的那样) 对于默认参数提升),行为是未定义的,除了以下内容 例:- 一种类型是有符号整数类型,另一种类型是相应的无符号整数类型,并且该值可在两种类型中表示;
- 一种类型是指向void的指针,另一种是指向字符类型的指针。
返回
在
type
宏之后第一次调用va_arg
宏返回va_start
指定的参数值。连续的调用返回 其余参数的值连续。212)允许创建指向va_list的指针并将该指针传递给另一个函数,其中 如果原始函数在另一个函数返回后可以进一步使用原始列表。
C89标准类似,但不支持/定义parmN
。