2010-07-13 2 views
3

(Вопрос связан с моими предыдущими вопросами here, here, here и here).Enum vs Macro States C++

Я поддерживаю очень старое приложение, перенесенное много лет назад с DOS на Windows, но многие старые конвенции C все еще переносятся вперед.

Тот частности конвенции является SetBit и clrBit макро:

#ifndef setBit 
#define setBit(word, mask) word |= mask 
#endif 

#ifndef clrBit 
#define clrBit(word, mask) word &= ~mask 
#endif 

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

enum SystemStatus 
{ 
    SYSTEM_ONLINE    = BIT0, 
    SYSTEM_STATUS2    = BIT1, 
    SYSTEM_STATUS3    = BIT2, 
    SYSTEM_STATUS4    = BIT3 
}; 

С BIT0 = 0x00000001, BIT1 = 0x00000002 и т.д.

SystemStatus systemStatus;

systemStatus = SYSTEM_ONLINE

По вашему мнению, использует SetBit и clrBit макросы более C нравится или C++, как - и это было бы лучше просто объявить переменные как перечисляемый тип и избавиться от всего старого материала setBit/clrBit?

+0

Как указывает Нейл, они не совсем то же самое. Тем не менее, на C++ вы никогда не должны использовать макросы как функции, вместо этого используйте функцию шаблона. Кроме того, для набора битов просто используйте 'std :: bitset' и делайте с ним. (Более удобный интерфейс.) – GManNickG

+0

Чтобы перечислить все возможные состояния таким образом, вам нужно 2^(количество бит) состояний. Наверное, не самое чистое решение. –

+4

@Justin Такова природа бит. – 2010-07-13 19:57:50

ответ

4

Я думаю, вы сбиваете с толку цели. Перечисление - это настройка значений для использования в качестве флагов. setBit и clrBit работают с данными. Эти данные могут оказаться флагом, но это действительно единственная связь между этими двумя идеями.

Это, как говорится, макросы, конечно, НЕ способ поведения C++. Вместо этого вы будете использовать встроенные функции. Например:

template<typename T> 
inline T& setBit(T& word, T mask) { return word |= mask; } 

template<typename T> 
inline T& clrBit(T& word, T mask) { return word &= ~mask; } 

Edit парировать nitpickers:

Это просто пример того, как можно реализовать функции. Вам не нужно использовать шаблоны, вы можете использовать два параметра шаблона вместо 1, вы можете использовать функцию void или значения вместо ссылок, если хотите, (хотя тогда она потеряет часть исходной семантики). Главное - получить преимущества безопасности типов, которые вы не найдете в макросах (среди многих других недостатков макросов). http://www.parashift.com/c++-faq-lite/inline-functions.html#faq-9.5

Edit: Вот пустота, не шаблон версия для сравнения

inline void setBit(unsigned int word, unsigned int mask) { word |= mask; } 

inline void clrBit(unsigned int word, unsigned int mask) { word &= ~mask; } 
+0

должен ли это быть 'template ' вместо этого? – 2010-07-13 19:56:33

+0

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

+0

В вашем примере я получаю 'Не удалось найти соответствие для setBit (unsigned int, SystemState)' – 2010-07-13 20:01:55

7

Нет, вы не можете - присвоение значения перечисления перезаписывает все значение, в то время как макросы меняют биты в существующем значении. И что такое BIT0, BIT1 и др.? Это похоже на определение INT0, INT1 и т. Д. - ужасная практика.

Нижняя линия, это старый код C-стиля, который дает вам какие-либо проблемы? Если нет, примените это соблюдаемое по времени правило - если оно не сломано, не исправляйте его.

+3

Если они не являются константами для нулевого, первого, второго и т. Д. Порядковых бит. Это не так. IMO легче читать, чем '0x00004000'. –

+1

@James Вы имеете в виду, что BIT0 может быть определен как (1 << 31) - о, это больно! Но возможно, я думаю. – 2010-07-13 19:37:30

+0

@Neil: Ну, я больше думал о том, чтобы начать отсчет с бит младшего порядка, но я думаю, что любой из них сработает. –

6

SetBit & clrBit прекрасны, хотя я бы преобразовать их в встроенные функции в C++. Они были бы очень удобно, если биты состояния являются независимы друг от друга, так что:

SystemStatus systemStatus = SYSTEM_ONLINE | SYSTEM_STATUS3; 

является допустимой настройкой.

systemStatus = clrBit(systemStatus, SYSTEM_STATUS3); 
systemStatus = setBit(systemStatus, SYSTEM_STATUS4); 
+0

+1: Действительно, установка Такие флаги являются обычным и приемлемым C++. Например, посмотрите на флаги «iostream». –

2

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

OK, если перечислений являются bitflags, так что вы могли бы написать

systemStatus = SYSTEM_ONLINE | BIT2; 

Тогда я думаю, что для чтения и может поддерживать комбинации, ок.

1

Использование enum, как вы это сделали, работает только в том случае, если вы можете гарантировать, что одновременно должно быть установлено не более одного бита. В противном случае вы должны иметь перечислимую константу для всех битовых комбинаций, которая может быстро быстро стать сложной. Вы можете использовать набор операторов #define (или enum, я полагаю) для псевдонима битмаски с дружественным именем, но вы все равно, вероятно, закончите использование макросов set/clear.

Установка и очистка бит определенно кажется более похожим на «C-подобный» подход. Тем не менее, я (лично) не считаю ваш подход enum очень «похожим на C++». Для более C++-подобного подхода создайте класс для представления состояния системы и манипулирования членами класса вместо битовых полей. Вы могли бы даже перегрузить операторы + и -, чтобы действовать как ваша функция setBit и clrBit, соответственно. Например, используя systemStatus -= SYSTEM_ONLINE#define SYSTEM_ONLINE (1<<31) или аналогичный), чтобы очистить бит «System Online», если и только если он установлен. Вы могли бы даже наследовать от STL Bitset и повторно использовать большую часть этой функциональности.

Редактировать: ОП разъяснил, что BIT0 и т. Д. Битмаски, поэтому мой первый абзац больше не имеет отношения к делу.

1

Я согласен с bta, если вы хотите использовать подход C++, вам следует создать класс, который абстрагирует всю реализацию о состояниях.

Но я не перегружаю + =, - = операторы, потому что вы продолжаете носить C старой школы.

Я предлагаю объявление метода для этого.

Вы можете выбрать один метод с булевым флагом или двумя для настройки & clear.

class Status{...}; 

void main(){ 
    Status status; 

    //first approach 
    status.SystemOnline(true); 
    status.BackUPOnline(false); 

    //second approach 
    status.SetEmergencySystem(); 
    status.ClearSystemOnline(); 
} 

с этим стилем вы инкапсулируете реализацию о том, как реализовать хранение информации.