6

If I have two integer values I can test for equality simply:

if (a == b)

if I have three integer values then I could do something like:

if ((a == b) && (a == c) && (b == c))

I've got a situation where I've got 6 values to test for equality, this approach is going to get verbose

Is their a better, and more C idiomatic (c-onic?) means to achieve this?

actually, just having written this I can see that:

if ((a == b) && (b == c) && (c == d)... )

is logically ok, i.e. you don't need all the combinations as a == b and b == c implies a == c

But in terms of clarity of expression how close can I get to:

if (a == b == c) ?

bph
  • 10,728
  • 15
  • 60
  • 135
  • 1
    Can you use an array for those 6 values? (so that you use a loop instead). – P.P May 05 '16 at 13:40
  • 1
    Store all of them into an array or vector and do bitwise XOR? If final answer is `0`, then `a===b==c`, else not. –  May 05 '16 at 13:40
  • 5
    @abhishek_naik 1^2^3==0 so 1==2 and 2==3? –  May 05 '16 at 13:40
  • 2
    However, if `(a|b|c|d|e|f)==a` and `(~a|~b|~c|~d|~e|~f)==~a` then I think we have it. I'm not sure I'd call that "clarity of expression" though. –  May 05 '16 at 13:41

4 Answers4

7

I can show you how to do it in a variadic macro, so we can write this:

if(EQI(a, b, c, d, e, f))

Here's the code:

#include <stdarg.h>
#include <stddef.h>

#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__}) / sizeof(int))
#define EQI(...) ( \
    alleqi(NUMARGS(__VA_ARGS__), __VA_ARGS__))

/* takes count number of int arguments */
int alleqi(size_t count, ...)
{
    va_list va;
    va_start(va, count);

    int v0 = va_arg(va, int);

    for (; count > 1; count--) {
        if (v0 != va_arg(va, int)) {
            break;
        }
    }

    va_end(va);
    return count == 1;
}

Please be advised the above only works for int arguments (and probably other types whose size is the same as int, though I am bracing for someone to accuse me of promoting undefined behavior if I advertise that!).

Thanks to this prior post for figuring out how to count arguments in a variadic macro: https://stackoverflow.com/a/2124433/4323

Community
  • 1
  • 1
John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • maybe INTEQ rather than EQ to adhere to principle of least surprise? – bph May 05 '16 at 14:02
  • 1
    @bph: I made it `EQI` now, though I think it's OK to use it on any four-byte quantities. We could make an `EQL` for eight-byte quantities. You can even `assert()` the size of the first argument is correct, but beyond that is tedious. – John Zwinck May 05 '16 at 14:20
  • Nice use of compound literal to determine `count`. – chux - Reinstate Monica May 05 '16 at 15:07
7

You're not going to get very close to a == b == c.

To cause experienced C programmers the least surprise, I think this is best is

if(a == b && b == c && c == d && d == e && e == f)

i.e. basically like what you have already, with less parentheses. I'm not always opposed to adding parentheses that make no difference to the compiler to help humans who don't know all the precedence rules, but I think comparisons separated by && (with no || mixed in) are a simple enough case that the parentheses are more clutter than they're worth.

If the variable names are long, putting it all on one line isn't going to be pretty, so maybe

if(a == b &&
   b == c &&
   c == d &&
   d == e &&
   e == f)

or this might be better since the duplication of the the a in every line will be immediately noticeable:

if(a == b &&
   a == c &&
   a == d &&
   a == e &&
   a == f)

If you really want it to be compact, the p99 preprocessor library offers this:

#include "p99_for.h"

if(P99_ARE_EQ(a,b,c,d,e,f))

which looks like John Zwinck's answer but doesn't require a helper function.

  • well this is pretty much what I implemented, keeping the left hand side the same is a nice touch - p99 is new to me and looks very interesting.. cheers for the heads-up – bph May 05 '16 at 14:41
  • crikey - the reference manual for p99 is over 1000 pages long! thats some header file.. – bph May 05 '16 at 14:50
6

If you want to check six values, one approach would be to store them in an array

int a[6];

equals = 1;
for (int i=0; i<5; i++)
{
    if (a[i] != a[i+1])
    {
       equals = 0;
       break;
    }
}
Rishikesh Raje
  • 8,556
  • 2
  • 16
  • 31
2

Approaches using arrays require you to change your data structure into an array.

Approaches using a variadic macro requires an additional function and function call (overhead).

Except for these two approaches, the only other way I see is to write them out. I feel the best way, or the more clear way, is to take the first variable and compare it to all other variables. By implication then either all variabes are equal, or at least two variables are unequal:

if ((a == b) && (a == c) && (a == d)
&&  (a == e) && (a == f) && (a == g) ...)
Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
  • 1
    That is actually for 7 variables. For 6 it's hardly worth doing anything else - just 5 comparisons. If OP had realised beforehand there is no need to test `b == c` etc, he might not have asked the question. – Weather Vane May 05 '16 at 14:16
  • Yes I did hesitate when posting the OP - but I have definitely learnt something so all good – bph May 05 '16 at 14:39