LINUX.ORG.RU

Функции с переменным числом аргументов: va_arg vs void*

 


0

2

Пытаюсь выбрать наиболее подходящий вариант. Речь идёт о тех случаях, когда количество и тип переменных заранее известно, но вызов должен происходить через некий интерфейс, как, например, через syscall. Фактически, я сейчас пытаюсь определиться между двумя вариантами:

int api1( unsigned int id, ... );
int api2( unsigned int id, const void* arg );

В случае api1 предполагается передавать набор аргументов в зависимости от id.

В случае api2 предполагается передавать указатель на некую структуру, которая будет отличаться в зависимости от id и в которой будет виден весь список аргументов.

Пока что склоняюсь ко второму способу, потому что, во-первых, структуру можно будет объявить заранее статически, а во-вторых, виден список аргументов. Цена вопроса - размер указателя.

А какой вариант предпочли бы вы? Или может существуют ещё способы?

★★★
Ответ на: комментарий от u5er

Не сомневаюсь, но при выборе языка удобство для меня - это не самый главный пункт ;)

Удобство ещё в том, что если нужно в а-ля Си коде можно использовать: std, …

Вообще сам не использую, так как разработал (и пополняю) своё API, которое весьма удобно.

В целом конечно - «на вкус и цвет, товарищей нет».

Пошучу

Как говорил кирпич подойдя к краю крыши другому кирпичу - «Главное, чтобы человек попался хороший».

anonymous
()
Ответ на: комментарий от u5er

Без сомнения, ты решишь эту задачу с помощью C. И второй вариант безусловно рабочий. Всё дело в том, что будет потом. Насколько это будет читабельно, развиваемо, тестируемо. Вот тут возникают вопросы. И другой язык тут более предпочтителен. При строгой типизации уже при компиляции ты найдешь ошибку, которую в C не нашел бы и она бы выскочила на проде. При явном использовании типов явно видно как добавлять новые типы, при использовании полиморфизма не придется делать страшный switch () из приведения от (void*). Ладно, простите за офтоп.

DenProg
()
Ответ на: комментарий от u5er

я определю список id и соответствующие данные, которые будут передаваться через указатель

Ну так не поступай как писатели printf (хотя там тоже много чего в оправдание можно сказать).

представь, что у printf() были бы заранее прописаны все возможные варианты и каждый вариант имел бы свой прототип

Вот об том и говорю, что надо мух от котлет отделять на месте, а не послезавтра. Делай тайпхинтинг и наследование структур на все типы пересылаемых данных — айди чего-то там, оно и будет опорой, если не хватит — добавь поле с типом сообщения. Не еби мозги.

deep-purple ★★★★★
()
Ответ на: комментарий от anonymous

В целом конечно - «на вкус и цвет, товарищей нет».

Немного офтопа.

А чем использование C++ в качестве а-ля Си плохо?

Например. перевёл freetype и SDL на C++ и всё ok!

anonymous
()
Ответ на: комментарий от u5er

Я знаю содердимое для конкретного id, но я не могу заранее предусмотреть id для всех возможных случаев. Именно в этом вся суть. Если бы я заранее мог знать все возможные варианты, то я бы сделал бы обычный api.

В теле своей функции ты перечисляешь все ID. Или switch/case, или if - else if - else if. Не суть.

А значит ты предусмотрел абсолютно все ID. В теле своей функции, а не навызывающей стороне. В чём разница?

her_s_gory ★★
()
Ответ на: комментарий от deep-purple

Ну так не поступай как писатели printf (хотя там тоже много чего в оправдание можно сказать).

Пошучу

Разработчики printf наверное не знают иных способов.

С использованием метаданных printf более ээфективен и универсален.

Для run-time такой подход - «шик, блеск, красота».

anonymous
()
Ответ на: комментарий от deep-purple

А поди загляни в реализацию ngx_printf и спрячь этот пафос поглубже ))

Смотрел конечно.
Пафоса нет.
Не знают.
Впрочем лишний раз посмотрю исходники (ранее не знали).

anonymous
()
Ответ на: удаленный комментарий

Потому анонимус, если ничего дельного не выдает, идет в жопу. Ну, выдай что-то красивое и по делу — ты же можешь.

deep-purple ★★★★★
()
Ответ на: комментарий от deep-purple

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

Есть задача - организовать общение между потоками. Одним из возможных решений является RPC(удалённый вызов процедур) - механизм, который позволяет вызвать функцию в другом процессе, передать ему аргумент и получить ответ. Эту штуку я и пытаюсь реализовать.

Представим, что есть 2 сервиса. Один - локальный проигрыватель музыки, второй удалённый, который отвечает за освещение. У каждого из них есть заголовочник со своим набором id и описанием того, что вместе с этим id передаётся (и передаётся ли вообще). Очевидно, что эти наборы будут полностью отличаться друг от друга, т.к. выполняют абсолютно разные задачи.

Допустим, я сделаю так, как ты решил - пропишу все id и структуры в заголовочнике механизма rpc. Что дальше? А дальше появляется условный вася пупкин и говорит: я хочу сделать автозапуск автомобиля, стоящего во дворе, и управление воротами, как мне это сделать через твой rpc? На что я справедливо развожу руками.

Теперь, когда я расписал всё более подробно, спрошу: почему бы мне не поступить так, как писатели printf, если я не знаю в данный момент список того, что будет передаваться при вызове, но об этом будет известно при использовании этого api?

u5er ★★★
() автор топика
Последнее исправление: u5er (всего исправлений: 1)
Ответ на: комментарий от her_s_gory

В чём разница?

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

u5er ★★★
() автор топика
Ответ на: комментарий от u5er

Тще (тно). Тут ты никак не уйдешь от реализации «появляется условный вася пупкин и говорит: я хочу сделать автозапуск автомобиля, стоящего во дворе, и управление воротами».

Ты пытаешься переложить личную головную боль на прослойку. Нет — прослоек, которые решат все твои бизнес-задачи — не существует. Тебе придется писать их самому. По каждому кейсу, раз уж ты сам сказал, что «развожу руками».

В любом случае тебе придется реализовывать каждый вид обрабатываемого сообщения — тебе от этого не уйти.

deep-purple ★★★★★
()
Ответ на: комментарий от deep-purple

Тут ты никак не уйдешь от реализации «появляется условный вася пупкин и говорит: я хочу сделать автозапуск автомобиля, стоящего во дворе, и управление воротами».

Ты пытаешься переложить личную головную боль на прослойку

Нет, я пытаюсь переложить всю головную боль на того, кто будет использовать этот механизм. Ибо это в его задачу будет входить определение всех аргументов, которые передаются при конкретном id и написание обёрток при желании. Если это будет вася пупкин с его воротами и автозапуском, то он сам решит, какие id передаёт и принимает его код и какие аргументы при этом используются. Я-то каким боком тут?

u5er ★★★
() автор топика
Ответ на: комментарий от deep-purple

Она используется для вызова функции из одного потока в другом и передачи аргументов. Должна быть возможность передавать произвольный набор аргументов. Какие именно аргументы передаются определяются непосредственно при использовании.

u5er ★★★
() автор топика

Если это голосование, то я за вариант 2. Понятнее, что будет происходить, есть надежда, что будет легче отловить испорченную память при ошибках в интерпретации аргументов.

blex ★★★★
()
Ответ на: комментарий от u5er

Структуру перед вызовом вы можете один раз заполнить, а потом миллион раз вызвать функцию. Копировать через стек вы будете на каждый вызов.

Некоторые поля структуры могут заполняться константами, в таком случае компилятор может это оптимизировать.

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

zx_gamer ★★★
()
Ответ на: комментарий от u5er

Представим, что есть 2 сервиса. Один - локальный проигрыватель музыки, второй удалённый, который отвечает за освещение. У каждого из них есть заголовочник со своим набором id и описанием того, что вместе с этим id передаётся (и передаётся ли вообще). Очевидно, что эти наборы будут полностью отличаться друг от друга, т.к. выполняют абсолютно разные задачи.

Понятно, функциональность должна легко расширяться в любую неизвестную заранее сторону да к тому же все это должно работать по сети

В таком случае, если не планируется передавать миллионы событий в секунду, то собственный ASCII-протокол или даже JSON видятся уже не самым худшим решением

alx777 ★★★
()
Последнее исправление: alx777 (всего исправлений: 2)