2010-05-20 3 views
3

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

void somefunc(int arg1, float arg2); 

но реализуется как

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

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

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

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

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

+0

Передайте указатель, если это важно. – kennytm

+0

Есть ли ограничение не только для продвижения по умолчанию? (И выравнивание defn./decl.?) –

+0

Я прочитал вопрос как «Как создать общий батут, который можно подключить во время выполнения, как любой случайный IMP с любым случайным набором аргументов?» Для этого varargs нельзя использовать. – bbum

ответ

3

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

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, period. Как говорит bbum, ABI отличается.

+0

Вам известно, работает ли это на устройстве? –

+0

Он должен работать везде, где поплавок 32-битный; вам может понадобиться «stdint.h» или «inttypes.h», если вы не замените тип uint32_t чем-то другим, но большинство компиляторов имеют эти дни. – alastair

+0

Не думаю, FWIW, что это будет хороший способ реализовать Objective-C runtime. Лучше сделать это так, как это делает Apple, хотя для этого нужен язык ассемблера. – alastair

6

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

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

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

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

0

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

2

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

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

Смежные вопросы