2013-07-30 2 views
1

У меня есть флагиПроверить битовые флаги, которые не могут сосуществовать друг с другом

int A = 1; 
int B = 2; 
int C = 4; 

Я хочу сделать чек, что только один флаг может быть установлен на функцию

check(A | B | C) ; // invalid 
check(A); // valid 
check(B); // valid 
check(B | C); // invalid 
void check(int flags) { 
    // check that if A is specified, then B and C can't 
    // check that if B is specified, then A and C can't 
    // check that if C is specified, then B and A can't 
} 

Как может Я достигла этого без тонких «заявлений»?

+0

как насчет 'switch'? – rocketboy

+0

C# и java? у вас была такая же проблема на обоих языках? – Steve

+1

Что вы хотите проверить точно? – Paniz

ответ

2

Возможно, не самое элегантное решение, но я думаю, что это должно работать:

bool check(int flags) { 
    int A = 1; 
    int B = 2; 
    int C = 4; 

    return 
     flags == 0 || 
     flags == A || 
     flags == B || 
     flags == C; 
} 
+0

Благодарим за редактирование, я не совсем обратил на это внимание. – MightyPork

+0

Это, пожалуй, самое простое решение вопроса. Предполагая, что 'A, B, C' определяются как константы в другом месте, то это однострочная функция. – GrahamS

6

Чтобы установить бит в положение n, вы хотите установить значение 2^n.

Итак, если вы хотите проверить, что указан только один из флагов, вы просто хотите узнать, является ли это число двух.

А вот вопрос о том, как сделать это: How to check if a number is a power of 2

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

+0

Сила двух И меньше или равна C. – GrahamS

+0

Я думаю, что если вы попытаетесь написать эту функцию, вы обнаружите, что это намного сложнее, просто проверяя четыре действительных значения ' flags' как @MightyPork. – GrahamS

+0

Да, это вполне возможно. Но если вы написали общую функцию, называемую 'hasOneBitSet', вы можете ее повторно использовать. Если вы никогда не будете добавлять более трех флагов, тогда проверка их по одному будет работать. Возрастное напряжение между общностью и реальной жизнью. Пригодность зависит от индивидуальных обстоятельств. – Joe

0

Почему не использовать использование Enum для ваших флагов и проверить, определено ли значение int в перечислении.

enum Flags 
{ 
    A = 1, 
    B = 2, 
    C = 4 
} 

void Check(int flags) 
{ 
    bool isValid = Enum.IsDefined(typeof(Flags), flags); 
    ... 
} 
0

Вот реализация с переключателем:

void check(int flags) { 
    swicth (flags & (A | B | C)) { 
    case A: 
    case B: 
    case C: 
    case 0: 
     return true; 
    default: 
     return false; 
    } 
} 

Он будет работать (в C#) только тогда, когда A, B и C являются литералы, т.е. отмечены const. В противном случае вы можете сделать то же самое с:

void check(int flags) { 
    int relevantPart = flags & (A | B | C); 
    return relevantPart == A || relevantPart == B || relevantPart == C || relevantPart == 0; 
} 

В противном случае использовать трюк питания двоих детей (от ответа Джо):

void check(int flags) { 
    int relevantPart = flags & (A | B | C); 
    return (relevantPart & (relevantPart - 1)) == 0; 
} 

Я предполагал, там может быть более значащих бит, чем три минимум бит, и их следует игнорировать. Я также предположил, что ни A, B, ни C не были действительны (это не существует в моей интерпретации).

0

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

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

namespace Shared.Enumerations 
{ 
    [Flags] 
    public enum TaskStatusEnum 
    { 
     NotSet = 0, 
     Open = 1, 
     Canceled = 2, 
     Complete = 4, 
     OnHold = 8, 
     Inactive = 32, 
     All = Open | Canceled | Complete | OnHold | Inactive 
    } 
} 

Мы делаем это, чтобы мы могли сказать, дать нам любую задачу, которая открыта или на удержание.

TaskList activeTasks = taskListManager.TaskList.FindAll(target.Name, target.TaskType, (TaskStatusEnum.Open | TaskStatusEnum.OnHold)); 

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

[TestMethod] 
public void checkEnumVals() 
{ 
     var ts = TaskStatusTestEnum.Open; 
     ts |= TaskStatusTestEnum.OnHold; 

     bool matchBoth = false; 
     if ((ts & TaskStatusTestEnum.OnHold) == TaskStatusTestEnum.OnHold && (ts & TaskStatusTestEnum.Open) == TaskStatusTestEnum.Open) 
      matchBoth = true; 

     Assert.IsTrue(matchBoth); 
} 

Я бы не предложил что-то подобное.