Лучшие практики для числа аргументов для подпрограмм в C - PullRequest
5 голосов
/ 02 июля 2010

Я недавно начал работать над разработкой API, написанных на C. Я вижу некоторые подпрограммы, которые ожидают 8 (Восемь) параметров, и мне кажется уродливым и громоздким передача 8 параметров при вызове этой конкретной подпрограммы.Мне было интересно, можно ли реализовать что-то более приемлемое и более чистое.

Ответы [ 9 ]

6 голосов
/ 02 июля 2010

Если несколько аргументов могут быть логически сгруппированы вместе, вы можете рассмотреть создание структуры, содержащей их, и просто передать эту структуру в качестве аргумента. Например, вместо того, чтобы передавать два значения координат x и y , можно вместо этого передать структуру POINT.

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

5 голосов
/ 02 июля 2010

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

4 голосов
/ 02 июля 2010

Да, 8 почти наверняка слишком много.

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

С муфтой, как правило, чем слабее, тем лучше.Интерфейс только через параметры («связывание данных») - это хорошая слабая связь, в то время как использование глобальных переменных («общая связь») - очень высокая связь.Когда у вас большое количество параметров, обычно случается так, что кто-то пытался скрыть свою общую связь с тонкой оболочкой передачи данных.Его плохой дизайн с лакокрасочным покрытием.

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

2 голосов
/ 02 июля 2010

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

edit: в c - классы будут похожи на структуры в этом случае.

1 голос
/ 02 июля 2010

Я предлагаю использовать структуры тоже. Может быть, вы хотите переосмыслить свой дизайн API.

Помните, что ваши API будут использоваться разработчиками, и было бы сложно использовать вызов функции с 8 параметрами.

0 голосов
/ 09 мая 2013

Еще одна вещь, которую вы можете сделать, это преобразовать некоторые параметры в состояние . Функции OpenGL имеют меньше параметров, потому что у вас есть такие вызовы, как:

glBindFramebuffer( .. ) ;
glVertexAttribPointer( .. ) ;
glBindTexture( .. ) ;
glBindBuffer( .. ) ;
glBindVertexArray( .. ) ;

// the actual draw call
glDrawArrays( .. ) ;

Все эти (glBind* вызовы типа) представляют «изменение состояния», все из которых будут влиять на следующий вызов отрисовки. Вообразите вызов ничьей с 20 с чем-то аргументами .. абсолютно неуправляемым!

Старый Windows C API для рисования также имел состояние, хранящееся внутри объектов «непрозрачный указатель» (HDC, HWND '..). Непрозрачный указатель - это, по сути, способ C создавать частные элементы данных, к которым у вас нет прямого доступа. Так, например, в API рисования Windows вы должны создать непрозрачный указатель HDC с помощью createDC. Вы можете установить внутренние значения DC через функции SetDC*, например SetDCBrushColor.

Теперь, когда у вас есть DC, настроенный на цвет и все, вы можете использовать функцию Rectangle для входа в DC. Вы передали HDC в качестве первого параметра, который содержал информацию о том, какую цветную кисть использовать и т. Д. Rectangle затем принимает только 5 параметров, hdc, x, y, ширину и высоту.

0 голосов
/ 02 июля 2010

Также представляется интересным рассмотреть этот вопрос не с точки зрения безобразия / не безобразия, а с точки зрения производительности.

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

Думаю, стоит попробовать.

0 голосов
/ 02 июля 2010

Один шаблон, используемый некоторыми API (например, pthreads), - это «объекты атрибутов», которые передаются в функции вместо набора отдельных аргументов.Эти объекты атрибутов являются непрозрачными структурами, с функциями для их создания, уничтожения, изменения и запроса.В целом это требует больше кода, чем просто выгрузка 10 аргументов в функцию, но это более надежный подход.Иногда стоит потратить немного лишнего кода, который может сделать ваш код более понятным.

Еще раз, для хорошего примера этого шаблона, смотрите API pthreads.Я написал длинную статью о разработке pthreads API пару месяцев назад, и это один из аспектов, которые я рассмотрел в нем.

0 голосов
/ 02 июля 2010

Если API кажется громоздким с таким количеством параметров, используйте указатель на структуру, чтобы каким-либо образом передать параметры, которые связаны .

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

  1. Фильтры с большим количеством полиномиальных коэффициентов.
  2. Преобразования цветового пространства с подпиксельными масками и индексами LUT.
  3. Геометрическая арифметика для n-мерных нерегулярных многоугольников.

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

...