1

I'm trying to represent card providers as an enum. Basically a credit card (based on BIN number) can be Visa or Mastercard, and the subtype can be Credit or Debit (simplified example, but I want to handle all cases (Maestro, Visa Electron, UATP...)

It seems to work, but see the last case it's possible to do CardProvider Visa | CardProvider MasterCard which is incorrect as we know.

I there a way to prevent this? Besides that is the current enum structure correct?

enum CardProvider
{
    CardProviderNone             = 0,
    CardProviderMasterCard       = 1 << 0,
    CardProviderMasterCardDebit  = 1 << 1,
    CardProviderMasterCardCredit = 1 << 2,
    CardProviderVisa             = 2 << 0,
    CardProviderVisaDebit        = 2 << 1,
    CardProviderVisaCredit       = 2 << 2
};

CardProvider cardType1 = CardProviderMasterCard;
CardProvider cardType2 = CardProviderMasterCard | CardProviderMasterCardCredit;
CardProvider cardType3 = CardProviderMasterCard | CardProviderMasterCardDebit;
CardProvider cardType4 = CardProviderVisa | CardProviderVisaDebit;

// possible to prevent?
CardProvider cardType5 = CardProvider Visa | CardProvider MasterCard;

// works as expected:
assert(cardType1 & CardProviderMasterCard);
assert(cardType2 & CardProviderMasterCardCredit);
assert(cardType2 & CardProviderMasterCard);
assert(cardType3 & CardProviderMasterCard);
assert(!(cardType4 & CardProviderMasterCard));
assert(cardType4 & CardProviderVisa);

// works but shouldn't be allowed
assert(cardType5 & CardProviderVisa);
Thomas Joulin
  • 6,590
  • 9
  • 53
  • 88

2 Answers2

1

You probably need to use separate enums for provider and type, and use sequential numbers instead of a bitmask:

enum CardProvider
{
    CardProviderNone             = 0,
    CardProviderMasterCard       = 1,
    CardProviderVisa             = 2
};

enum CardType
{
    CardTypeNone              = 0,
    CardTypeDebit             = 1,
    CardTypeCredit            = 2
};
dbush
  • 205,898
  • 23
  • 218
  • 273
0

Your card types are overlapping (2<<0 == 1<<1) You just need to adjust them so they aren't. There are many different ways, but this is what it looks like you were trying to do.

typedef enum CardProvider {
    CardTypeNone                 = 0,
    CardTypeCredit               = 1<<0,
    CardTypeDebit                = 1<<1,
    /* you may want to add padding here for extra card types */

    CardProviderMasterCard       = 1<<2,
    CardProviderMasterCardDebit  = CardTypeDebit  | CardProviderMasterCard,
    CardProviderMasterCardCredit = CardTypeCredit | CardProviderMasterCard,

    CardProviderVisa             = 1<<3,
    CardProviderVisaDebit        = CardTypeDebit  | CardProviderVisa,
    CardProviderVisaCredit       = CardTypeCredit | CardProviderVisa,
    //future providers here
};

int card_transaction(CardProvider, float amount, struct card_data);

To make the compiler error on misuse, see https://stackoverflow.com/a/14822654/1162141

Community
  • 1
  • 1
technosaurus
  • 7,676
  • 1
  • 30
  • 52