我想调用一个函数来调出一个菜单,如下所示:
Mode_Menu("Item 1", "Item A1c", "Item Fred", ..... "Item xxx")
,其中n
可以是任何合理的数字,每个项目可以是随机长度。
我尝试了以下(忽略Offer_Mode
中的数字 - 这只是LCD上的Y
坐标)
void Mode_Menu(char *m1, ...)
{
va_list argp;
va_start(argp, *m1);
Offer_Mode(2, m1++);
Offer_Mode(33, m1++);
Offer_Mode(64, *m1++;
Offer_Mode(97, *m1++);
Offer_Mode(130, *m1++);
}
但我得到的是
Item 1
tem 1
em 1
m 1
1
即,指针沿着第一个元素移动,甚至从未看到函数调用中的第二个元素。
我已经尝试了所有我能想到的咒语,在函数定义和*m1[]
中使用像m1[2]
或va_start
这样的东西,但是我尝试的所有内容都会引发错误。
有人能指出我这样做的正确方法吗?
(我已经首先进行了广泛的搜索,所以请不要将其标记为重复。有很多使用整数的例子但我没有使用char数组找到的例子)。
vardiac模板的C接口使它成为:
void Mode_Menu(char *arg, ...)
{
va_list argp;
va_start(argp, &arg);
Offer_Mode(2, arg);
arg=va_arg(argp, char*)
Offer_Mode(33, arg);
arg=va_arg(argp, char*)
Offer_Mode(64, arg);
....
va_end(argp);
}
编辑:实际的代码应该有办法找出参数的结束。它可以是整数第一个参数,来自字符串信息(如printf格式,或字符串中的模式匹配),或者是nullptr sentinel(最后一个参数)。
C ++方式(使用SFINAE检查类型的正确性)
template <typename ...T>
std::enable_if_t<(std::is_same_v<T, char>&&...)>
Mode_Menu(const T*... args)
{
const char * texts[] = { args... };
Offer_Mode(2, texts[0]);
Offer_Mode(33, texts[1]);
Offer_Mode(64, texts[2]);
....
}
编辑2:模板变体已经包含sizeof...(T)
和std::size(texts)
中的大小信息。因此,与C变体不同,不需要努力检测最后一个字符串。
我重复我在评论中已经说过的话:
在C ++中,我更喜欢可变参数模板,或者可能是在容器中提供参数(例如std :: vector)。如果那根本不是一个选项,那么我会使用va_arg来访问参数。而且,请不要忘记va_end()。如果不小心使用,处理va_宏中的可变参数可能非常依赖于平台且易碎。
然而,(只记得我自己试图在过去的时候类似printf()
)一个样本:
#include <iostream>
#include <cstdarg>
void printMenu(int len, ...)
{
va_list argp;
va_start(argp, len);
for (int i = 0; i < len; ++i) {
const char *item = va_arg(argp, const char*);
std::cout << '[' << (i + 1) << "]: " << item << '\n';
}
va_end(argp);
}
int main()
{
printMenu(3, "Item 1", "Item A1c", "Item Fred");
return 0;
}
输出:
[1]: Item 1
[2]: Item A1c
[3]: Item Fred
笔记:
nullptr
参数)。关于printf()
,预期参数的数量直接取决于formatter参数的内容。 (因此,printf()
被认为是脆弱和不安全的。)您可以解决指定要传递的其他参数的数量。
必须从列表中“提取”每个附加参数。
我使用cout
因为我不知道Offer_mode
做了什么。
#include<iostream>
#include <stdarg.h>
void Mode_Menu(char *m1, unsigned int count,...);
int main(int argc, char* argv[])
{
Mode_Menu("Item 1", 3,"Item A1c", "Item Fred", "Item xxx");
return 0;
}
void Mode_Menu(char *m1, unsigned int count, ...)
{
va_list ap;
va_start(ap, count); /* Requires the last fixed parameter (to get the address) */
for (int j = 0; j < count; j++)
{
std::cout<<va_arg(ap, char*)<<std::endl; //ap automatically incremented
}
va_end(ap);
}