The definition of one operator in a conditional expression is true

I have a number of signals that can be true, false or invalid, but only one of them can be true, otherwise it will be a mistake.

I want to know if there is a way to test this easily and not make a big if statement

enum sig_type
{
  sig_invalid, sig_true, sig_false
};

sig_type sig1 = GetSignal("sig1");
sig_type sig2 = GetSignal("sig1");
sig_type sig3 = GetSignal("sig1");
sig_type sig4 = GetSignal("sig1");

if (sig1 == sig_true)
{
  if (sig2 == sig_true || sig3 == sig_true || sig4 == sig_true)
  {
    // Error
  }
}
else if (sig2 == sig_true)
{
  if (sig1 == sig_true || sig3 == sig_true || sig4 == sig_true)
  {
    // Error
  }
}

etc ... which is a significant amount of code and only increases when I add signals, so in this state it will be uncontrollable

+4
source share
5 answers

You can use the fact that logical expressions in C are evaluated to 0 for false or 1 for true and sum them together. If the amount is greater than 1, you have an error, otherwise you will not do it.

, , ( ), . for:

sig_type sig[NSIGNALS];
int t = 0;

for (int i = 0; i < NSIGNALS; ++i) {
    char buf[50];   /* Make sure your buffer is large enough, of course */
    sprintf(buf, "sig%d", i + 1);    /* Or however you want to generate it */
    sig[i] = GetSignal(buf);
    t += sig[i] == sig_true;
}

if (t > 1) {
    /* Complain */
}

, 1 , t > 1 t != 1.

EDIT: throw, C.

+6

, .

, , , :

const sig_type* sigs [number_of_sig] = 
{
  &sig1,
  &sig2,
  ...
};

.

bool one_sig_true = false;

for(int i=0; i<number_of_sig; i++)
{
  if(*sigs[i] == sig_true)
  {
    if(one_sig_true)    // if one was already true from before
    {
      error();
      break;
    }

    one_sig_true = true; // otherwise, set this flag
  }
}

// if the loop finished without error, everything is fine
+3

, value , 1:

value & (value-1)

Here's how you can use this trick to achieve your goal with a single operator if:

enum sig_type
{
    sig_inv   = 0,
    sig_true  = 1,
    sig_false = 2,
};

int b0 = (int)GetSignal("sig1") & 1;
int b1 = (int)GetSignal("sig1") & 1;
int b2 = (int)GetSignal("sig1") & 1;
int b3 = (int)GetSignal("sig1") & 1;

int value = (b0<<0) | (b1<<1) | (b2<<2) | (b3<<3);
if (value & (value-1))
{
    // Error
}
+2
source

just make your code remember the "state" in the variable.

enum sig_type
{
    sig_invalid, sig_true, sig_false
};

sig_type sig1 = GetSignal("sig1");
sig_type sig2 = GetSignal("sig1");
sig_type sig3 = GetSignal("sig1");
sig_type sig4 = GetSignal("sig1");

int count = 0;

if (sig1 == sig_true) {
    count++;
}
if (sig2 == sig_true) {
    count++;
}
if (sig3 == sig_true) {
    count++;
}
if( sig4 == sig_true) {
    count++;
}

if (count > 1) {
    /* your error code here */
}
+1
source

I would suggest a solution with arithmetic. I have the advantage that you get a good place for real things. In addition, you do not need any loop that can clear the command pipeline.

enum sig_type
{
  sig_invalid, sig_true, sig_false
};

sig_type sig1 = GetSignal("sig1");
sig_type sig2 = GetSignal("sig1");
sig_type sig3 = GetSignal("sig1");
sig_type sig4 = GetSignal("sig1");

// This can be rewritten as needed and the personal preferences. 
// The arithmetic that is described in this answer remains.
int cumulative_result = 
    ((sig1 == sig_true) << 0) |
    ((sig2 == sig_true) << 1) |
    ((sig3 == sig_true) << 2) |
    ((sig4 == sig_true) << 3));

switch (cumulative_result)
{
case 0:
case 1:
case 2:
case 4:
case 8:
    break;
default:
    /* your error code here */
    break;
}

You may be more specific for cases that are also “more evil”.

+1
source

Source: https://habr.com/ru/post/1546663/


All Articles