验证变量参数是否为预期类型

发布于 2024-11-17 05:01:32 字数 327 浏览 2 评论 0原文

我目前正在编写一个函数,该函数将采用可变数量的参数。我将参数数量传递给函数,然后迭代参数列表。

每个传递的参数都应该是一个整数。我将把这个整数添加到稍后将使用的整数向量中。

我想确保某些小丑将来不会尝试将此函数传递给除整数之外的其他内容。我认识到我可以检查 va_arg 中的当前参数以确保它不为 NULL,并且我可以使用 isanum(va_arg()) 之类的东西来确定它是否是有效的整数。我想我什至可以检查 sizeof(va_arg) 并将其与 sizeof(int) 进行比较并确保它们相等。

我可以运行任何其他检查来验证我是否已传递了有效的整数?

预先感谢您的帮助

I'm currently writing a function which will take a variable number of arguments. I pass the number of arguments into the function and then will iterate through the arguments list.

Each of the passed arguments should be an integer. I will be adding this integer to a vector of integers which will be used later.

I would like to make sure that some joker doesn't attempt to pass this function something other then an integer in the future. I recognize that I can check the current argument from va_arg to ensure it is not NULL and I can use something like isanum(va_arg()) to determine if it is a valid integer. I suppose I could even check the sizeof(va_arg) and compare it against the sizeof(int) and ensure they are equal.

Are there any other checks which I can run to verify I have been passed a valid integer?

Thanks in advance for assistance

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

满天都是小星星 2024-11-24 05:01:32

没有明智的方法可以做到这一点。可变参数函数的工作原理是将参数的所有原始二进制表示形式连接到堆栈上的一大块数据中。因此,它依赖于调用者和被调用者就参数的数量和类型达成一致(否则您最终将读取 int ,就好像它是 float)。

至于您的具体想法:

  • va_arg() 是一个宏,它简单地将原始堆栈数据的一些字节解释为您指定的任何类型。因此,对其调用 sizeof() 只会告诉您所需的数据类型的大小。

  • 一般来说,原始二进制数据不存在形成无效整数的模式。因此,假设的 isanum() 无法工作。

There is no sensible way you can do this. Variable-argument functions work by concatenating all the raw binary representations of the arguments into one big chunk of data on the stack. So it relies on both the caller and the callee agreeing on what the number and type of arguments are (otherwise you'll end up reading e.g. an int as if it were a float).

As to your specific ideas:

  • va_arg() is a macro that simply interprets some number of bytes of the raw stack data as whatever type you specify. So invoking sizeof() on it will simply tell you the size of the data type you asked for.

  • In general, there are no patterns of raw binary data that form an invalid integer. So the hypothetical isanum() could not work.

暗恋未遂 2024-11-24 05:01:32

每个传递的参数都应该是一个整数。

如果您有 C++0x 编译器,我建议使用 initializer_list 而不是 varargs:

#include <initializer_list>

void foo(std::initializer_list<int> numbers)
{
    my_vector.insert(my_vector.end(), numbers.begin(), numbers.end());
}

int main()
{
    foo( {2, 3, 5, 7} );
}

这是直接且完全类型安全的。

Each of the passed arguments should be an integer.

If you have a C++0x compiler, I suggest an initializer_list<int> instead of varargs:

#include <initializer_list>

void foo(std::initializer_list<int> numbers)
{
    my_vector.insert(my_vector.end(), numbers.begin(), numbers.end());
}

int main()
{
    foo( {2, 3, 5, 7} );
}

This is straight-forward and completely type-safe.

凌乱心跳 2024-11-24 05:01:32

每个传递的参数应该是
一个整数。我将添加这个
整数到整数向量,其中
稍后会用到。

那么为什么不只接受整数向量呢?

void AddIntegers(const std::vector<int>& vec);

然后,您始终可以使用迭代器将向量连接在一起。

或者创建一个像这样的接口:

void AddInteger(int newInt);

甚至这样:

void AddIntegers(const int* integers, unsigned int numIntegers);

template <unsigned int Size>
void AddIntegers(int (&integers)[Size])
{
    AddIntegers(integers, Size);
}

int main()
{
    int i[] = {1, 2, 3, 4};
    AddIntegers(i);
}

如果您需要使用 C++03 编译器,这些将起作用。如果您有 C++0x 编译器,则可以使用更高级的解决方案。

Each of the passed arguments should be
an integer. I will be adding this
integer to a vector of integers which
will be used later.

Then why not just accept a vector of integers?

void AddIntegers(const std::vector<int>& vec);

You can then always concatenate vectors together using iterators.

Or make an interface like this:

void AddInteger(int newInt);

Or even this:

void AddIntegers(const int* integers, unsigned int numIntegers);

template <unsigned int Size>
void AddIntegers(int (&integers)[Size])
{
    AddIntegers(integers, Size);
}

int main()
{
    int i[] = {1, 2, 3, 4};
    AddIntegers(i);
}

These will work if you need to work with a C++03 compiler. If you have a C++0x compiler, there are far superior solutions available.

冰魂雪魄 2024-11-24 05:01:32

可变参数在设计上是不安全的。您无法以任何方式检查用户是否传递了正确的类型。 C++0x 通过可变参数模板来救援,但现在没有多少编译器支持它(据我所知,只有 GCC)。

Variable arguments are unsafe by design. You cannot check that the user passed correct type in any way. C++0x comes to the rescue with variadic templates but not many compilers support it nowadays (only GCC afaik).

孤蝉 2024-11-24 05:01:32

不幸的是,确实没有办法做到这一点。像 printf() 这样的函数很容易通过传递无效或错误数量的参数而被搞乱。

在 C++ 中,这是一项高级功能,需要使用此类代码进行编程以确保传递正确的参数。

Unfortunately, there really isn't a way to do this. Functions like printf() can easily be fowled up by passing invalid or the wrong number of arguments.

In C++, this is an advanced feature that requires the programming using such code to ensure the correct arguments are passed.

少钕鈤記 2024-11-24 05:01:32

您无法使用可变参数进行任何类型的检查。我建议改用迭代器范围(如标准库函数)或可能使用 std::vector。这样类型就无法被破坏。

You can't do any sort of type checking with varargs. I'd suggest using an iterator range instead (like standard library functions) or possibly a std::vector<int>. This way the types can't be subverted.

又怨 2024-11-24 05:01:32

既然您使用的是 C++,那么重载一些运算符并一一传递参数怎么样?例如

class MyFunction {
  std::vector<int> param;
  public:
  MyFunction() { /* some initialisation? */ }
  MyFunction &operator,(int eatMe) {
    param.push_back(eatMe);
    return *this;
  }
  ~MyFunction() {
     //the implementation of your function goes here
  }
}

然后你可以这样调用它:

MyFunction(),2,3,5,7;

注意,使用逗号运算符可能看起来很可怕,但在这种情况下它实际上非常有帮助。它是最低可能的左结合运算符。

如果您的函数需要一些额外的参数,而不仅仅是未知长度的 int-s,您可以在构造函数中传递它们。

如果有人使用 int 以外的其他内容,则将使用默认的逗号运算符(评估左侧、丢弃、评估右侧)。如果您不喜欢这样 - 选择不同的运算符,例如类似流的 << 或类似 boost 的 %

Since you are using C++, how about overloading some operator and pass the arguments one-by-one? For example

class MyFunction {
  std::vector<int> param;
  public:
  MyFunction() { /* some initialisation? */ }
  MyFunction &operator,(int eatMe) {
    param.push_back(eatMe);
    return *this;
  }
  ~MyFunction() {
     //the implementation of your function goes here
  }
}

Then you can call it like this:

MyFunction(),2,3,5,7;

Note, the use of comma operator may look scary, but it is actually very helpful in this case. It is the lowest possible, left-associative operator.

If your function takes some extra parameters, not only the unknown-length of int-s, you can pass them in the constructor.

If someone uses something else than int, the default comma operator will be used (evaluate left side, discard, evaluate right side). If you don't like that - pick a different operator, e.g. stream-like << or boost-like %.

微暖i 2024-11-24 05:01:32

如果您仅限于 C++03 并且所有参数都应该是整数,则一种解决方案是简单地隐藏可变参数函数(例如在“详细”命名空间中)并创建一系列 1 到 N 数量的重载函数的论点。这些函数将是简单的内联函数,它将调用转发到实际函数的 vararg 版本。这样,您就有了一个真正的实现,没有运行时开销,并且向调用者公开了一个类型安全的接口(如果调用者需要超过 N 个参数,则始终可以使用 vararg 版本)。

Boost.PP 还可以帮助生成这些类型的重复模式。

当然,如果您有一定程度的 C++0x 支持,那么问题可以通过多种方式解决,包括初始化列表或可变参数模板。

If you are restricted to C++03 and all your arguments should be integers, one solution would be to simply hide the variable argument function (in a 'detail' namespace for example) and make a series of overloaded functions for 1 to N amount of arguments. Those functions would be simple inline functions that forward the call to the vararg version of the real function. This way, you have one real implementation, no run-time overhead, and you expose a type-safe interface to the caller (and the caller can always use the vararg version if he needs more than N arguments).

Boost.PP can also help to generate these types of repetitive patterns.

Of course, if you have some level of C++0x support, than the problem can be solved in many ways, including initializer_list or variadic templates.

美煞众生 2024-11-24 05:01:32

只是为了说明我对 CygnusX1 答案的评论,您可以这样做:

class MyFunction {
  std::vector<int> params;
  public:
  MyFunction() { (*this)(); }
  MyFunction(int eatMe) { (*this)(eatMe); }
  MyFunction& operator()(int eatMe) {
    params.push_back(eatMe);
    return *this;
  }
  void operator()() { 
    // use params to do something interesting
  }
}

MyFunction(2)(3)(5)(7)();

Just to illustrate my comment on CygnusX1's answer, you could do it like:

class MyFunction {
  std::vector<int> params;
  public:
  MyFunction() { (*this)(); }
  MyFunction(int eatMe) { (*this)(eatMe); }
  MyFunction& operator()(int eatMe) {
    params.push_back(eatMe);
    return *this;
  }
  void operator()() { 
    // use params to do something interesting
  }
}

MyFunction(2)(3)(5)(7)();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文