Почему полиморфные вызовы (например, слушатель в каутах) имеют анонимные аргументы, а не непрозрачные указатели и функции доступа?

Я смотрю на техническую ноту каут , но об этом конкретно не говорится . Это скорее общий дизайн API.

Объем слушателя:

static int MyListener( kauth_cred_t credential, void * idata, kauth_action_t action, uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3 ); 

arg0arg3 зависят от области действия (т.е. контекста). Процитировать документацию:

Смысл остальных параметров зависит от объема. в последующих разделах … Например, для области VFS (KAUTH_SCOPE_VNODE) ​​arg1 является ссылкой на vnode (типа vnode_t), который работает

Я предполагаю, что есть веская причина для этого дизайна, но я не вижу его. Что делать, если я хочу добавить аргументы позже? Что делать, если я хочу передать типы разного размера (в этом случае uintptr_t typedefed для unsigned long но что, если я хочу передать более крупную структуру?).

Пример такой проблемы можно увидеть в том же документе:

ВАЖНО: при проверке учетных данных, связанных с запросом, всегда используйте функции доступа, определенные в sys / kauth.h. Будьте особенно внимательны при тестировании членства в группах. В Tiger пользователь может быть в нескольких группах (гораздо больше, чем традиционный лимит в 16), и группы могут быть вложенными. Если вы хотите проверить, является ли пользователь членом группы, используйте kauth_cred_ismember_gid.

Если бы я реализовал функцию API, которая может быть вызвана с разными аргументами в разных контекстах, я бы передал непрозрачный тип (т.е. void * ) и предоставил набор функций для извлечения данных из него. Функции меняются с помощью API, будущая защита.

Итак, может ли кто-нибудь объяснить, почему авторы, возможно, выбрали этот проект для остальных аргументов? Это чистая скорость (в конце концов, коды кодов kauth невероятно горячие)?

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

Итак, если целые числа являются общим случаем, тогда вы получаете лучшее из обоих миров:

  • Никаких хлопот по общему делу и никаких сомнений / несоответствий в передаче целых чисел (маскируйте их как указатель или передайте указатель на целое число)
  • По-прежнему можно передать указатели, если вам нужно (ссылка на) большую структуру.

Портативный и расширяемый способ реализации функции, которая принимает переменное количество аргументов, состоит в том, чтобы объявить ее переменной:

 #include  static int MyListener (kauth_cred_t credential, void* idata, kauth_action_t action, ... { va_list ap; int count = some_context_dependend_count; int j; va_start(ap, count); for (j = 0; j < count; j++) do_something_with_each_optional_arg (va_arg(ap, uintptr_t); va_end(ap); return some_result; }