какой из этих двух лучше?
void SetBit(int *flag, int bit)
{
*flag |= 1 << bit;
}
Или
int SetBit(int flag, int bit)
{
flag |= 1 << bit;
return flag;
}
Второй мне нравится, потому что он не имеет побочных эффектов. Если вы хотите изменить флаг
, вы можете просто присвоить результат самому себе:
flag = SetBit(flag, 4);
Ни то, ни другое.
int SetBit(int flag, int bit)
{
return flag | 1 << bit;
}
Это зависит от обстоятельств.
первый - императивный стиль, второй - функциональный.
Если хочешь сделать
SetBit(SetBit(... SetBit(flag, b1), b2),...), bn)
, сделай второй. Если хотите
SetBit(&flag, b1)
SetBit(&flag, b2)
...
SetBit(&flag, bn)
, сделайте первый. В C я бы предпочел последнее (т.е. императивное). В других языках / контекстах первое может быть хорошей идеей.
Я бы использовал макрос:
#define BIT_SET(a, bit) ((a) | (1 << (bit)))
Мне больше нравится второй ...
Однако я бы рекомендовал изменить имя вашей функции, чтобы оно было более наглядным (при условии, что это настоящее имя). «SetBit» не очень хорошо описывает, что функция делает или возвращает:)
Честно говоря, я думаю, что это просто побуждает людей использовать «магические числа» в качестве флагов:
SetBit(&flags, 12); // 12 is the flag for Super mode
На самом деле вам нужны имена констант:
#define SUPERMODE_FLAG 12
...
SetBit(&flags, SUPERMODE_FLAG);
Но если вы собираетесь используйте именованные константы, вы также можете называть маски, а не номера битов, и в этом случае операция настолько проста, что нет необходимости во вспомогательной функции:
#define SUPERMODE_MASK (1 << 12)
....
flags |= SUPERMODE_MASK;
В необычном случае, когда вы манипулируете отдельными битами по номеру, не зная, что они означают, то я предпочитаю второй по той же причине, что и Кристо - я считаю, что функции без побочных эффектов немного легче рассуждать, чем мутаторы.
Второй лучше, потому что он не вылетит.
Первый будет может дать сбой, если вы передадите неверный указатель NULL , поэтому вам понадобится код для проверки и обработки этого.
Это зависит от того.
В этом случае действительно подойдет любой способ. Но я могу вспомнить два особых случая, когда я бы предпочел использовать указатель.
Если тип, который вы передаете, большой и копирование значения будет дорогостоящим, используйте указатель из соображений производительности.
Если вам нужно вернуть что-то еще, возможно, код состояния или индикатор успеха/неудачи, то вам нужно использовать указатель, чтобы оставить место для возврата значения, которое вам нужно вернуть.
Я лично думаю, что вне этих ситуаций второй вариант (передача/возврат по значению) более понятен и немного более читабелен.
Во-первых, нормально, если функции будут встроены. Без встраивания это слишком много накладных расходов, чтобы передавать указатели на целые числа. (В 64-битных архивах LP64 int - 4 байта, указатель - 8.)
Второе ... имя функции SetBit () может вызвать некоторую путаницу. Название подразумевает, что функция что-то меняет, а на самом деле - нет. Если вы согласны с названием, то это лучший вариант с точки зрения производительности.
Например. Ядро Linux для многих подобных вещей использует вариант указателя, поскольку часто расположение данных в памяти важно или требуется для переносимости. Но они либо делают все такие функции макросом препроцессора, либо помечают атрибут gcc always_inline. Для пользовательского программирования простых приложений я бы сказал, что предпочтение должно быть отдано второму. Только выберите лучшее имя.
Если единственным шаблоном использования функции будет «переменная = doSomething (переменная);» и производительность не является проблемой, я бы рассмотрел "doSomething (& variable);" чтобы быть более разборчивым. Единственный раз, когда я предпочел бы первое, было бы, если бы местом назначения иногда было что-то иное, чем источник, или если бы производительность была критичной, и компилятор не мог эффективно обрабатывать последний случай (часто встречается во встроенных системах).
Следует отметить, что последний формат позволяет то, что не позволяет первый. В стиле VB:
Sub OrBits(ByRef N as Integer, ByVal Bits as Integer) Dim OldValue as Integer Do OldValue = N Loop While Threading.Interlocked.CompareExchange(N, OldValue or Bits, OldValue) <> OldValue End Sub
Результатом этого кода всегда будет ИЛИ указанных битов на N, даже если что-то еще изменит N во время выполнения функции. Невозможно добиться такого поведения с помощью стратегии чтения и возврата.
Передайте int
, чтобы сэкономить время на разыменовании указателя.