Есть ли способ получить float из параметров функции varargs? - PullRequest
3 голосов
/ 20 мая 2010

Если функция была определена с помощью прототипа, в котором явно указаны типы параметров, например.

void somefunc(int arg1, float arg2);

, но реализовано как

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

возможно ли использовать va_arg для получения числа с плавающей точкой? Обычно это не разрешается делать, потому что функции varargs имеют неявные продвижения типов, такие как float to double, поэтому попытка получить необращенный тип не поддерживается, даже если функция вызывается с необращенным типом do для более конкретного прототипа функции. *

Причиной этого является получение аргументов разных типов во время выполнения в составе интерпретатора obj-c, где одна функция будет повторно использоваться для всех методов разных типов.

Лучше всего, если это не зависит от архитектуры (так что если на симуляторе и на устройстве больше не работает один и тот же код), хотя, если нет способа сделать это, будут приняты исправления, специфичные для устройства.

EDIT: забыл особо упомянуть: функция знает типы и количество аргументов (она ищет код, который будет интерпретирован с помощью поиска по карте с параметром SEL _cmd)

Ответы [ 4 ]

6 голосов
/ 20 мая 2010

Для этого вам, скорее всего, придется использовать сборку для каждой архитектуры. Во-первых, вы не можете использовать varargs, потому что, как вы и предполагали, вызывающий ABI для varargs отличается от вызывающего ABI для не-varargs; аргументы кодируются по-разному, а состояние регистра отличается по границе вызова.

Самый простой способ сделать это - создать массу функций-заглушек со всеми вариантами аргументации, которые вам когда-либо понадобятся. Затем каждая заглушка принимает конкретные аргументы и объединяет их в нечто более общее для более общего использования вашего кода.

Если вы не хотите идти по этому пути, вам нужно знать типы аргументов, правила кодирования для аргументов для конкретного целевого ABI, а затем вам нужно будет написать код для эффективно вырвать аргументы из своих секретных дыр, когда ваш общий батут называется.

И вам нужно будет сделать все это, в то же время не уничтожая любой из аргументов путем непреднамеренного использования регистра. Возможно, вы обнаружите, что моя статья objc_msgSend () косвенно полезна, поскольку она точно описывает, как Objective-C справляется с этой проблемой (подсказка: она идет на все, чтобы не touch) любой из аргументов, кроме первых двух).

3 голосов
/ 20 мая 2010

Вы можете сделать следующее:

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

тогда всегда вызывайте вашу функцию так:

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

В своей функции вы бы тогда сделали

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
}

Это устраняет проблему ненужных продвижений типов и не требует ассемблера.

Конечно, вы не должны неправильно объявлять свою функцию. Если это функция varargs, то это функция varargs, точка. Как говорит Bbum, ABI отличается.

2 голосов
/ 20 мая 2010

Если функция объявлена ​​и определена так, как вы показываете, нет способа что-либо сделать, особенно независимо от архитектуры. Код не работает. Не работает Абсолютно нет совместимости между вариационными и невариантными функциями в C. Это функции совершенно разной природы, они принадлежат двум совершенно различным непересекающимся мирам.

Если в вашей конкретной реализации / архитектуре эти два могут быть каким-то образом вынуждены работать вместе, это конкретная деталь вашей реализации. В этом случае вы должны исследовать вашу конкретную архитектуру.

0 голосов
/ 20 мая 2010

Вы всегда можете отказаться от varargs и вместо этого закодировать все свои параметры в строку.Ваш функциональный интерфейс остается постоянным, и вы имеете полную свободу интерпретировать данные так, как вам нужно.Однако это не очень хорошее решение, поскольку вы по сути реализуете синтаксический анализатор скриптов.

...