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

标签 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);

}

我得到非法指令。

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

最佳答案

当您调用带有可变参数列表的函数时(这在 C++ 中通常是个坏主意),然后任何 float表达式会自动提升(转换)为 double , 和任何 char (三种口味中的任何一种)和short (两种口味)被提升为int .因此,正如错误消息所说,您不能指望 va_arg()收集floatchar类型;你需要收集一个doubleint并在必要时强制转换结果。

一般来说,C++ 程序员不喜欢可变参数列表函数,因为它们本质上不是类型安全的,而 C++ 为类型安全投入了大量精力。

1998 年的 C++ 标准基本上合并了 (1989) C 标准规范 <stdarg.h>逐字。 1999 C 标准说:

§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 parameter ap shall have been initialized by the va_start or va_copy macro (without an intervening invocation of the va_end212) macro for the same ap). Each invocation of the va_arg macro modifies ap so that the values of successive arguments are returned in turn. The parameter type 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 * to type. If there is no actual next argument, or if type 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 the va_start macro returns the value of the argument after that specified by parmN. 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.

C89标准类似但不支持/定义va_copy .

关于c++ - c++中具有不同数据类型的变量参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8366290/

相关文章:

c++ - 使用 CMakeLists.txt 设置 Qt5 - 找不到文件错误

c++ - fork_rv 返回什么?

c++ - 初始化列表覆盖动态多维数组的内存

c++ cout如何打印char*

c++ - 建议具有良好 C++ 接口(interface)的高效 SAT 求解器(或 : is Z3 good for me)?

c++ - 方括号数组

c++ - 在许多类中使用具有相同标识符的 #define 会导致 "error: <ID> redefined"

通过 COM 端口的 C++ 通信

c++ - 为什么不支持从 template<typename T1, typename T2> 到 template<typename T1, int i> 的类特化

c++ - 使用 spawnl 并等待子进程退出