Функции C, злоупотребляющие параметрами? - PullRequest
3 голосов
/ 31 марта 2009

У меня есть устаревшая база кода C на работе, и я нахожу множество реализаций функций в стиле ниже.

char *DoStuff(char *inPtr, char *outPtr, char *error, long *amount)
{
    *error = 0;
    *amount = 0;

    // Read bytes from inPtr and decode them as a long storing in amount
    // before returning as a formatted string in outPtr.

    return (outPtr);
}

Использование DoStuff:

myOutPtr = DoStuff(myInPtr, myOutPtr, myError, &myAmount);

Я нахожу это довольно тупым, и когда мне нужно реализовать подобную функцию, я в итоге выполняю:

long NewDoStuff(char *inPtr, char *error)
{
    long amount = 0;
    *error = 0;

    // Read bytes from inPtr and decode them as a long storing in amount.

    return amount;
}

Использование NewDoStuff:

myAmount = NewDoStuff(myInPtr, myError);
myOutPtr += sprintf (myOutPtr, "%d", myAmount); 

Не могу не спросить, есть ли что-то, чего мне не хватает в верхнем примере, есть ли веская причина для использования такого подхода?

Ответы [ 5 ]

1 голос
/ 31 марта 2009

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

Кроме того, возвращение указателя out позволяет вам выполнять такие действия, как:

DoOtherStuff(DoStuff(myInPtr, myOutPtr, myError, &myAmount), &myOther);

При вашем новом подходе эквивалентный код становится намного более подробным:

myAmount = DoNewStuff(myInPtr, myError);
myOutPtr += sprintf("%d", myAmount);
myOther  = DoOtherStuff(myInPtr, myError);
myOutPtr += sprintf("%d", myOther);
1 голос
/ 31 марта 2009

Это стандартный стиль библиотеки C. Возвращаемое значение используется для помощи в цепочке вызовов функций.

Кроме того, DoStuff чище ИМО. И вы действительно должны использовать snprintf. И изменения во внутреннем буфере управления не влияют на ваш код. Тем не менее, это больше не верно с NewDoStuff.

0 голосов
/ 31 марта 2009

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

Я бы предпочел первую функцию, но я также довольно привык к стандартному стилю C.

0 голосов
/ 31 марта 2009

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

0 голосов
/ 31 марта 2009

Код, который вы представили, немного неясен (например, почему вы добавляете myOutPtr с результатами sprintf.

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

Разделение обязанностей на две функции - хорошая идея. Тем не менее, вы бы хотели иметь отдельную функцию для этого объединения и форматирования, это действительно не ясно.

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...