有没有办法从varargs函数的参数中检索浮点数?

时间:2022-06-22 03:58:20

If the function was defined with a prototype which explicitly stated the types of the parameters, eg.

如果函数是用一个原型来定义的,这个原型明确地说明了参数的类型,例如。

void somefunc(int arg1, float arg2);

but is implemented as

但被实现为

void somefunc(int arg1, ...) { ... }

is it possible to use va_arg to retrieve a float? It's normally prevented from doing this because varargs functions have implicit type promotions, like float to double, so trying to retrieve an unpromoted type is unsupported, even though the function is being called with the unpromoted type do to the more specific function prototype.

是否可以使用va_arg检索一个浮点数?通常不允许这样做,因为varargs函数具有隐式类型提升,比如float to double,所以不支持尝试检索未提升类型,即使用未提升类型do对更具体的函数原型进行调用。

The reason for this is to retrieve arguments of different types at runtime, as part of an obj-c interpreter, where one function will be reused for all different types of methods.

这样做的原因是在运行时检索不同类型的参数,作为object -c解释器的一部分,其中一个函数将用于所有不同类型的方法。

This would be best as architecture independent (so that if nothing else the same code works on simulator and on device), although if there is no way to do this then device specific fixes will be accepted.

这最好是独立于体系结构(因此,如果在模拟器和设备上没有相同的代码的话),尽管如果没有办法做到这一点,那么设备特定的修复将被接受。

EDIT: forgot to mention specifically: the function knows the types and count of the arguments (it looks up the code to be interpreted with a map lookup with the SEL _cmd parameter)

编辑:忘记特别提到:函数知道参数的类型和计数(它查找要用带有SEL _cmd参数的映射查找来解释的代码)

4 个解决方案

#1


3  

You could do the following:

你可以这样做:

static inline uint32_t floatparam (float f) {
  union { uint32_t u; float f; } u;
  u.f = f;
  return u.u;
}

then always call your function like so:

然后一直调用你的函数:

fn(5, floatparam(0.5f), floatparam(1.1f), ...);

In your function, you'd then do

在你的函数中,你会这样做

va_list val;

va_start (val, arg1);
while (<more arguments>) {
  union { float f; uint32_t u; } u;
  u.u = va_arg (val, uint32_t);
  // float is now in u.f
}

That avoids the problem of needless type promotions, and doesn't require assembly language.

这避免了不必要的类型升级问题,并且不需要汇编语言。

Of course, you shouldn't mis-declare your function. If it's a varargs function, it's a varargs function, period. As bbum says, the ABI is different.

当然,您不应该错误地声明函数。如果它是一个varargs函数,它是一个varargs函数,周期。正如bbum所说,ABI指数是不同的。

#2


6  

You are pretty much going to have to use per-architecture assembly to do this. First, you can't use varargs because -- as you implied -- the calling ABI for varargs is different than the calling ABI for non-varargs; arguments are encoded differently and the register state is different across the call boundary.

要做到这一点,几乎必须使用每个体系结构的程序集。首先,您不能使用varargs,因为正如您所暗示的,varargs的调用ABI与非varargs的调用ABI是不同的;参数的编码不同,在调用边界上的寄存器状态也不同。

The easiest way to do this is to create a ton of stub functions w/all the variations of argumentation you'll ever need. Each stub then takes the specific arguments and bundles 'em up into something more general for your code's more general consumption.

要做到这一点,最简单的方法是创建大量的存根函数w/所有您需要的各种参数。然后,每个存根都接受特定的参数,并将它们捆绑成更通用的代码,以供您的代码更一般的使用。

If you don't want to go that route, then you are going to have to know the types of the arguments, the encoding rules for arguments for the particular target ABI, and then you'll need to write the code to effectively rip the arguments out of their hidy-holes when your generic trampoline is called.

如果你不想走这条路,那么你将不得不知道的类型参数,参数的编码规则为特定目标ABI,然后你需要编写代码有效裂缝参数的hidy-holes当你调用通用的蹦床。

And you'll need to do all that while also not destroying any of the arguments through inadvertent register use. You might find my write-up of objc_msgSend() to be indirectly useful in that it describes exactly how Objective-C handles this issue (hint: it goes to great lengths to not touch any of the arguments beyond the first two).

你需要做所有的事情,同时也不要因为疏忽的注册使用而破坏任何参数。您可能会发现我对objc_msgSend()的描述是间接有用的,因为它确切地描述了Objective-C如何处理这个问题(提示:除了前两个参数外,没有涉及任何参数)。

#3


2  

If the function is declared and defined as you show, there's no way to do anything, especially in architecture-independent way. The code is broken. It doesn't work. There's absolutely no compatibility between variadic and non-variadic functions in C. These are functions of completely different nature, they belong to two completely different non-intersecting worlds.

如果函数是在显示时声明和定义的,就没有办法做任何事情,特别是以与体系结构无关的方式。坏了的代码。它不工作。在c中,变量和非变量函数完全不相容,它们是性质完全不同的函数,它们属于两个完全不同的不相交的世界。

If in your specific implementation/architecture these two can be somehow forced to work together, this is a specific detail of your implementation. In that case you have to research your specific architecture.

如果在您的特定实现/体系结构中,这两种方法可以被强制协同工作,那么这就是实现的具体细节。在这种情况下,你必须研究你的特定架构。

#4


0  

You can always ditch varargs and instead encode all of your parameters into a string. Your function interface remains constant, and you have complete freedom to interpret the data however you need to. It's not a pretty solution, however, since you're essentially implementing a script parser.

您总是可以丢弃varargs,而将所有参数编码为字符串。函数接口保持不变,可以*地解释数据。不过,这并不是一个很好的解决方案,因为实际上您正在实现一个脚本解析器。

#1


3  

You could do the following:

你可以这样做:

static inline uint32_t floatparam (float f) {
  union { uint32_t u; float f; } u;
  u.f = f;
  return u.u;
}

then always call your function like so:

然后一直调用你的函数:

fn(5, floatparam(0.5f), floatparam(1.1f), ...);

In your function, you'd then do

在你的函数中,你会这样做

va_list val;

va_start (val, arg1);
while (<more arguments>) {
  union { float f; uint32_t u; } u;
  u.u = va_arg (val, uint32_t);
  // float is now in u.f
}

That avoids the problem of needless type promotions, and doesn't require assembly language.

这避免了不必要的类型升级问题,并且不需要汇编语言。

Of course, you shouldn't mis-declare your function. If it's a varargs function, it's a varargs function, period. As bbum says, the ABI is different.

当然,您不应该错误地声明函数。如果它是一个varargs函数,它是一个varargs函数,周期。正如bbum所说,ABI指数是不同的。

#2


6  

You are pretty much going to have to use per-architecture assembly to do this. First, you can't use varargs because -- as you implied -- the calling ABI for varargs is different than the calling ABI for non-varargs; arguments are encoded differently and the register state is different across the call boundary.

要做到这一点,几乎必须使用每个体系结构的程序集。首先,您不能使用varargs,因为正如您所暗示的,varargs的调用ABI与非varargs的调用ABI是不同的;参数的编码不同,在调用边界上的寄存器状态也不同。

The easiest way to do this is to create a ton of stub functions w/all the variations of argumentation you'll ever need. Each stub then takes the specific arguments and bundles 'em up into something more general for your code's more general consumption.

要做到这一点,最简单的方法是创建大量的存根函数w/所有您需要的各种参数。然后,每个存根都接受特定的参数,并将它们捆绑成更通用的代码,以供您的代码更一般的使用。

If you don't want to go that route, then you are going to have to know the types of the arguments, the encoding rules for arguments for the particular target ABI, and then you'll need to write the code to effectively rip the arguments out of their hidy-holes when your generic trampoline is called.

如果你不想走这条路,那么你将不得不知道的类型参数,参数的编码规则为特定目标ABI,然后你需要编写代码有效裂缝参数的hidy-holes当你调用通用的蹦床。

And you'll need to do all that while also not destroying any of the arguments through inadvertent register use. You might find my write-up of objc_msgSend() to be indirectly useful in that it describes exactly how Objective-C handles this issue (hint: it goes to great lengths to not touch any of the arguments beyond the first two).

你需要做所有的事情,同时也不要因为疏忽的注册使用而破坏任何参数。您可能会发现我对objc_msgSend()的描述是间接有用的,因为它确切地描述了Objective-C如何处理这个问题(提示:除了前两个参数外,没有涉及任何参数)。

#3


2  

If the function is declared and defined as you show, there's no way to do anything, especially in architecture-independent way. The code is broken. It doesn't work. There's absolutely no compatibility between variadic and non-variadic functions in C. These are functions of completely different nature, they belong to two completely different non-intersecting worlds.

如果函数是在显示时声明和定义的,就没有办法做任何事情,特别是以与体系结构无关的方式。坏了的代码。它不工作。在c中,变量和非变量函数完全不相容,它们是性质完全不同的函数,它们属于两个完全不同的不相交的世界。

If in your specific implementation/architecture these two can be somehow forced to work together, this is a specific detail of your implementation. In that case you have to research your specific architecture.

如果在您的特定实现/体系结构中,这两种方法可以被强制协同工作,那么这就是实现的具体细节。在这种情况下,你必须研究你的特定架构。

#4


0  

You can always ditch varargs and instead encode all of your parameters into a string. Your function interface remains constant, and you have complete freedom to interpret the data however you need to. It's not a pretty solution, however, since you're essentially implementing a script parser.

您总是可以丢弃varargs,而将所有参数编码为字符串。函数接口保持不变,可以*地解释数据。不过,这并不是一个很好的解决方案,因为实际上您正在实现一个脚本解析器。