c ++中具有不同数据类型的变量参数

时间:2011-12-03 07:25:47

标签: c++

请仔细阅读以下代码

#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.

如何解决这个问题......这是处理这类问题的正确方法吗?

1 个答案:

答案 0 :(得分:3)

当您使用可变参数列表调用函数时(在C ++中通常是一个坏主意),任何float表达式都会自动提升(转换)为double,并且任何{{1 (三种风格中的任何一种)和char(两种风格)被提升为short。因此,正如错误消息所示,您不能指望int收集va_arg()float类型;您需要收集chardouble并在必要时强制执行结果。

一般来说,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应该由。初始化   apva_start宏(没有干预va_copy 212的调用)   同一个va_end的宏。 ap宏的每次调用都会修改va_arg以便{。}}   连续参数的值依次返回。参数ap应为类型   指定的名称,使得指向具有指定类型的对象的指针的类型可以   只需将type后缀为*即可获得。如果没有实际的下一个参数,或者如果   type与实际的下一个参数的类型不兼容(正如提升的那样)   对于默认参数提升),行为是未定义的,除了以下内容   例:

     

- 一种类型是有符号整数类型,另一种类型是相应的无符号整数类型,并且该值可在两种类型中表示;

     

- 一种类型是指向void的指针,另一种是指向字符类型的指针。

     

返回

     

type宏之后第一次调用va_arg宏返回   va_start指定的参数值。连续的调用返回   其余参数的值连续。

     

212)允许创建指向va_list的指针并将该指针传递给另一个函数,其中   如果原始函数在另一个函数返回后可以进一步使用原始列表。

C89标准类似,但不支持/定义parmN