从C中可变参数函数的参数确定类型

让-巴蒂斯特·布希耶(Jean-Baptiste Bouhier)

我想逐步解释如何解析可变参数的参数,以便调用va_arg(ap,TYPE); 我传递了要传递的参数的正确数据类型。

目前,我正在尝试对printf进行编码。我只想找一个解释最好用简单的例子,但不是解决对printf,因为我想解决这个个人挑战自己的进步。

Link1link2link3是示例,我认为它们是我所查找内容的一部分。我了解typedef,struct,enum和union的基础知识,但无法弄清楚某些实际的应用案例,例如链接中的示例。

他们到底是什么意思?我无法为他们的工作方式着迷。如何像链接示例中那样将数据类型从联合传递给va_arg?它如何匹配?使用%d,%i ...等修饰符或参数的数据类型?

到目前为止,这是我得到的:

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include "my.h"

typedef struct s_flist
{
    char c;
    (*f)();
}              t_flist;

int     my_printf(char *format, ...)
{
    va_list ap;
    int     i;
    int     j;
    int     result;
    int     arg_count;
    char    *cur_arg = format;
    char    *types;
    t_flist flist[] = 
    {
        { 's',  &my_putstr  },
        { 'i',  &my_put_nbr },
        { 'd',  &my_put_nbr }
    };

    i = 0;
    result = 0;
    types = (char*)malloc( sizeof(*format) * (my_strlen(format) / 2 + 1) );
    fparser(types, format);
    arg_count = my_strlen(types);

    while (format[i])
    {
        if (format[i] == '%' && format[i + 1])
        {
            i++;
            if (format[i] == '%')
                result += my_putchar(format[i]);
            else
            {
                j = 0;
                va_start(ap, format);
                while (flist[j].c)
                {
                    if (format[i] == flist[j].c)
                        result += flist[i].f(va_arg(ap, flist[i].DATA_TYPE??));
                    j++;
                }
            }
        }
        result += my_putchar(format[i]);
        i++;
    }

    va_end(ap);
    return (result);
}

char    *fparser(char *types, char *str)
{
    int     i;
    int     j;

    i = 0;
    j = 0;
    while (str[i])
    {
        if (str[i] == '%' && str[i + 1] &&
            str[i + 1] != '%' && str[i + 1] != ' ')
        {
            i++;
            types[j] = str[i];
            j++;
        }
        i++;
    }
    types[j] = '\0';
    return (types);
}
杂种

您无法从获得实际的类型信息va_list您可以从获得所需的东西format您似乎并不期望的是:没有一个参数知道实际的类型是什么,但是format代表了调用者对类型应该什么的想法(也许还暗示:会是什么实际 printf?怎么做,如果呼叫者给它的可变参数传递会注意到它不匹配的格式说明)

您的代码将必须解析“%”格式说明符的格式字符串,并使用这些说明符分支以读取va_list具有特定硬编码类型的。例如,(pseudocode)if (fspec was "%s") { char* str = va_arg(ap, char*); print out str; }由于您明确表示您不想要完整的解决方案,因此没有提供更多详细信息。


编辑添加:

您将永远不会将类型作为可va_arg作为值传递给运行时数据的部分的第二个参数va_arg必须是在编译时引用已知类型的文字硬编码规范。(请注意,这va_arg是一个在编译时扩展的宏,而不是在运行时执行的函数-您不能有一个将类型作为参数的函数。)

您的几个链接建议通过枚举来跟踪类型,但这仅出于您自己的代码能够基于该信息进行分支的好处。它仍然不是可以传递给的东西va_arg您必须使用单独的代码按字面说va_arg(ap, int)va_arg(ap, char*)所以无法避免aswitchifs

您想要使用并集和结构创建的解决方案将从以下内容开始:

typedef union {
  int i;
  char *s;
} PRINTABLE_THING;

int print_integer(PRINTABLE_THING pt) {
  // format and print pt.i
}
int print_string(PRINTABLE_THING pt) {
  // format and print pt.s
}

通过采用显式intchar*参数,这两个专用功能可以很好地发挥作用我们进行并集的原因是使函数能够正式采用相同类型的参数,从而使它们具有相同的签名,以便我们可以定义一个单一类型,该类型表示指向该类型函数的指针

typedef int (*print_printable_thing)(PRINTABLE_THING);

现在,您的代码可以具有type的函数指针数组print_printable_thing,或者具有print_printable_thing作为struct字段之一的struct数组

typedef struct {
  char format_char;
  print_printable_thing printing_function;
} FORMAT_CHAR_AND_PRINTING_FUNCTION_PAIRING;

FORMAT_CHAR_AND_PRINTING_FUNCTION_PAIRING formatters[] = {
  { 'd', print_integer },
  { 's', print_string }
};
int formatter_count = sizeof(formatters) / sizeof(FORMAT_CHAR_AND_PRINTING_FUNCTION_PAIRING);

(是的,这些名称都是有意的超级冗长。您可能希望在实际程序中使用较短的名称,或者在适当的情况下甚至希望使用匿名类型。)

现在,您可以使用该数组在运行时选择正确的格式化程序:

for (int i = 0; i < formatter_count; i++)
  if (current_format_char == formatters[i].format_char)
    result += formatters[i].printing_function(current_printable_thing);

但是,将正确的内容放入其中的current_printable_thing过程仍将涉及分支,以va_arg(ap, ...)使用正确的硬编码类型来获得a 编写完之后,您可能会发现自己实际上并不需要联合或结构数组。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

从C中可变参数函数的参数确定类型

来自分类Dev

可变参数函数-确定返回类型

来自分类Dev

动态确定C中函数参数的类型?

来自分类Dev

C中的可变参数函数

来自分类Dev

C 函数中的可变参数

来自分类Dev

可变参数模板函数确定函数指针的返回类型

来自分类Dev

可变参数模板函数确定函数指针的返回类型

来自分类Dev

Haskell中的可变参数函数类型类

来自分类Dev

在C ++中可变参数模板中是否有对函数参数实施类型限制的好方法?

来自分类Dev

获取C99可变参数函数的参数类型

来自分类Dev

多类型参数的可变函数

来自分类Dev

C ++中的嵌套可变参数函数

来自分类Dev

类型球拍中可变参数函数的类型是什么?

来自分类Dev

类型球拍中可变参数函数的类型是什么?

来自分类Dev

以数组为参数在C ++中调用可变参数函数

来自分类Dev

C ++中没有参数可变参数模板函数

来自分类Dev

将参数传递给C中的可变参数函数

来自分类Dev

以可变参数作为函数C ++的参数的函数

来自分类Dev

可变参数(类似printf)函数中的类型模糊

来自分类Dev

具有可变参数化和类型的C函数指针

来自分类Dev

C ++:如何在可变参数模板参数上调用带有类型参数的函数?

来自分类Dev

函数中参数的可变顺序

来自分类Dev

函数参数中的可变借位

来自分类Dev

函数中参数的可变顺序

来自分类Dev

使用可变参数函数C ++

来自分类Dev

绑定可变参数函数C ++

来自分类Dev

可变参数函数中的默认参数提升

来自分类Dev

C ++-可变参数函数的多个参数包

来自分类Dev

确定Eclipse中函数参数的适当父类型