如何使用 va_arg "extract" long double?

How to "extract" a long double using va_arg?

我正在学习 C 编程,但遇到了一个问题。我想 "extract" 从参数列表中得到一个 long double。但是,当我问 va_arg 到 "catch" 一个长的双精度参数时,我有一个随机错误(正如 man 中提到的关于 va_arg 错误调用)。 但是我怎么可能解决这个问题呢? 这是说明 pb 的代码示例:

void func(va_list *ptr)
{
    long double f;

    f = va_arg(*ptr, long double);
    printf("Value extracted: %Lf\n", f);
    return ;
}

void func2(char *format, ...)
{
    va_list ap;

    va_start(ap, format);
    func(&ap);
    va_end(ap);
    return ;
}

感谢您的帮助!

编辑:我知道如何使用 va_arg(至少对于简单的东西)。如您所见,该函数将指向 va_list 的指针作为参数。这是因为我在调用函数中调用了 va_start(并且在同一个调用函数的末尾调用了 va_end)。我只是想向您展示问题所在。

我对其他数据类型(int、long、char、char *等)没问题。这只是一个长双铅。

编辑 #2:我写了一个调用函数来向您展示我没有忘记 va_start 和 va_end。最后,我的问题是我正在尝试编写我自己的 printf 函数并且我正在处理 -Lf 转换。我认为没有必要提及它,对此感到抱歉。

您的代码存在许多问题,包括缺少 va_startva_end,但要解决您的具体问题:

va_arg函数期望在调用时知道类型;类型参数是 you 告诉它 "hey, the argument is this type",而不是 "get the next argument in the list that has this type" 这就是我猜你认为它基于你的问题所做的。

一般来说,在汇编级别,在将类型传递给函数时确实没有任何关于类型的信息——没有调试信息。这就是 va_arg 需要该参数的原因,以及 printfscanf 等可变参数函数需要有关在其格式字符串中处理的类型的信息的原因。

如果设计一个接受不同类型的可变参数函数,您需要考虑不同的可能类型;格式字符串是一种方式。

您仍然没有向我们展示您正在使用的完整、可编译的代码,因此很难看出您做错了什么。这里有一些完整的代码,可以说明您要执行的操作。

#include <stdarg.h>
#include <stdio.h>

void vlist_one_ldouble(va_list *pargs) {
    long double value;

    value = va_arg(*pargs, long double);
    printf(" %Lf", value);
}

void vlist_ldouble(int count, va_list *pargs) {
    printf("Now printing %d long doubles:\n", count);

    for (int i=0; i<count; i++)
        vlist_one_ldouble(pargs);

    printf("\n");
}

void list_ldouble(int count, ...) {
    va_list args;
    va_start(args, count);

    vlist_ldouble(count, &args);

    va_end(args);
    return;
}

int main(void) {
    long double a = 1.1, b=2.2, c=3.3;

    list_ldouble(3, a, b, c);
    list_ldouble(4, 1.1L, 2.2L, 3.3L, 4.4L);

    return 0;
}

如果没有您的完整代码,我们无法检查的一件非常重要的事情是,您必须确保您确实传递了长双打。这里我用两种方式来做:首先,使用 long double 变量;其次是长双文字。

这里的L后缀就是一个"typed literal"的例子。当您在源代码中指定变量的实际值时(例如 13.14'b'"foo")这是一个文字。通常您不必明确指定文字的 type 是什么,因为编译器可以进行任何必要的转换。对于浮点文字,标准是这样说的:

An unsuffixed floating constant has type double. If suffixed by the letter f or F, it has type float. If suffixed by the letter l or L, it has type long double.

如果用字面值调用带有原型的标准函数,例如 func(1.2),那么编译器将知道 func() 是否期望一个 float、double 或 long double 并传递函数的适当类型。但是对于可变长度参数列表函数,没有原型可以使用,因此编译器从您传递的值的类型开始工作。如果您传递 1.2,它将作为双精度传递。如果你想传递一个 long double,你必须指定你的 1.2 实际上是一个 long double,这就是 L 的用途。如果您最终传递了一个双精度值,但期望一个长双精度值,您将不会得到您期望的值。

我找不到一个理想的参考,但是 this page isn't bad, and these pages 很好,但是是关于 C++,而不是 C。

如果这不能解决您的问题,post 一个完整的、可编译的程序,它没有达到您的预期。