char数组的变量参数

问题描述 投票:1回答:3

我想调用一个函数来调出一个菜单,如下所示:

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数组找到的例子)。

c++ arrays char variadic
3个回答
1
投票

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变体不同,不需要努力检测最后一个字符串。


1
投票

我重复我在评论中已经说过的话:

在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

Live Demo on coliru

笔记:

  1. 一个难点是正确识别可变参数的数量。我用了这个数。另一个经常使用的选项是注释结尾(例如使用nullptr参数)。关于printf(),预期参数的数量直接取决于formatter参数的内容。 (因此,printf()被认为是脆弱和不安全的。)
  2. 参数中只有某些类型可以预期。更多关于这里:Variadic arguments - Default conversions

1
投票

您可以解决指定要传递的其他参数的数量。

必须从列表中“提取”每个附加参数。

我使用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);
}
© www.soinside.com 2019 - 2024. All rights reserved.