Is there any way to retrieve a float from a varargs function's parameters?

限于喜欢 提交于 2019-12-24 00:18:35

问题


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.

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.

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)


回答1:


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.




回答2:


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.

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.

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.

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).




回答3:


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.

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:


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.



来源:https://stackoverflow.com/questions/2875670/is-there-any-way-to-retrieve-a-float-from-a-varargs-functions-parameters

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!