C函数中的可选参数

时间:2015-01-06 09:33:58

标签: c function arguments

在C函数中,我想检查输入参数(在我的情况下是'value')是否存在。

即:

void Console(char string[], int32_t value)
{
    // write string here
    // write value here, if it exists
}

使用if(value != NULL)语句时,我的Console()函数发送4096

我如何根据参数存在进行检查和行动?

3 个答案:

答案 0 :(得分:8)

C中通常不允许使用可选参数(但它们存在于C++Ocaml等中......)。唯一的例外是variadic functions(例如printf)。

顺便说一下,您可以定义一些宏来填充“缺失”参数,所以如果你有

  void console(const char*, int32_t);

你也可能

  #define console_plain(Msg) console((Msg),0)

这可能是某些标题中的一些内联函数,例如

  static void inline console_plain (const char*msg) 
  { console(msg, 0); }

然后在其他地方使用console_plain("hello here")

然后你的可变函数应该定义允许的参数和参数(在固定参数的非空序列之后)。并使用stdarg(3)来获取这些可变参数(实际)。

实际参数主要在编译时知道,而不是在运行时。因此,您需要一个约定,该约定通常定义从所需的固定参数中允许哪个可变参数。特别是,您无法测试是否存在参数(该信息在运行时丢失)。

BTW,使用可变函数,您通常会丢失大多数C编译器提供的类型检查(至少在您启用所有警告时,例如gcc -Wall -Wextra)。如果使用GCC  你可能在原型中有一些function __attribute__-s(如formatsentinel,....)来帮助它。您甚至可以使用MELT自定义gcc,以添加自己的属性进行自己的类型检查。

答案 1 :(得分:2)

如果要区分带有一个或两个参数的函数调用,可以使用宏。

虽然您可以重现您想要的行为,但有一些事项需要注意:

  • 宏实现隐藏了代码的随意读者的重载,他们无法看到Console是一个宏。 C非常关注细节,所以如果你有两个不同的函数,它们应该有不同的名称,可能是cons_strcons_str_int

  • 如果传递两个以上的参数或者参数与所需类型C string和int不兼容,宏将生成编译器错误。这实际上是件好事。

  • 使用printf接口的<stdarg.h>等真正的可变函数必须能够导出可变参数的类型和数量。在printf中,这是通过%格式说明符完成的。宏可以根据参数的数量在不同的实现之间切换。

无论如何,这是一个实现。谨慎行事。

#include <stdlib.h>
#include <stdio.h>

#define NARGS(...) NARGS_(__VA_ARGS__, 5, 4, 3, 2, 1, 0)
#define NARGS_(_5, _4, _3, _2, _1, N, ...) N

#define CONC(A, B) CONC_(A, B)
#define CONC_(A, B) A##B

#define Console(...) CONC(Console, NARGS(__VA_ARGS__))(__VA_ARGS__)



void Console1(const char string[])
{
    printf("%s\n", string);
}

void Console2(const char string[], int32_t value)
{
    printf("%s: %d\n", string, value);
}

int main()
{
    Console("Hello");
    Console("Today's number is", 712);

    return 0;
}

答案 2 :(得分:2)

这听起来好像是在尝试使用hackery来帮助自己或者“在写入模式下”打开源代码的人。 我说“处于写入模式”(不是读/写)因为这些代码很难读取,因为所有隐藏的代码,因为你需要的神奇的宏。 C不是一种智能语言。编译器可能很聪明,但语言语义相当迂腐。你应该严格遵守规则,否则你冒着制作坏软件的风险或更糟糕 - 根本不工作。

在不创建全新编程语言的情况下执行此操作的“正确”方法是提供两个参数,当不应使用第二个参数时,如果它是指针,则应将其作为NULL传递或者一些排除的数字,如-1,如果它是数字类型。

另一种方法是使用提示名称创建两个单独的函数,例如: consoleconsole_full。分别有一个和两个论点。

但如果您对上述方法仍然不满意,可以加入stdarg.h为您完成。

void Console (char *string, ...) /* Note the ... */
{
    va_list param;
    int32_t optValue = (-1); /* -1 would indicate optValue is to be ignored */

    // write string here

    va_start(param, string);

    optValue = va_arg(param, int32_t);

    if(optValue != (-1))
    {
        /* Work with `optValue` */
    }

    va_end(param);
}

哪种方式不好,因为你不知道附加参数的类型,也不知道它们有多少。要知道这些事情,你应该像printf一样的函数做,解析字符串中的特定标记,表明存在一个参数,它是什么类型的参数,或者至少只使用参数的const变量计数器。 你可以进一步宏观地计算参数的计数是自动的。