Which is more portable / is there a better way?

O

octangle

Create enumerated values using the three highest bits as bit flags that
define comparison operators.

VERSION A:
----------

enum eCriteria
{
eCriteriaOne = 1,
eCriteriaTwo = 2,
eCriteriaEtc = 9999,

eLess = 1 << ((sizeof(enum eCriteria) * 8) - 3),
eEqual = 1 << ((sizeof(enum eCriteria) * 8) - 2),
eGreater = 1 << ((sizeof(enum eCriteria) * 8) - 1),
}

VERSION B:
----------

enum eCriteria
{
eCriteriaOne = 1,
eCriteriaTwo = 2,
eCriteriaEtc = 9999,

eLess = ~(((unsigned int)(~0)) >> 1) >> 2,
eEqual = ~(((unsigned int)(~0)) >> 1) >> 1,
eGreater = ~(((unsigned int)(~0)) >> 1),
}

These bit flags are intended to be or'ed into other enumerated values
to indicate how these values are to participate in an underlying SQL
Select statement.

e.g.

{
/* <= Criteria 2 */

enum eCriteria lCriteria = eCriteriaTwo | eLess | eEqual;
}
 
P

pete

octangle said:
(unsigned int)(~0)

(~0) is not a portable value.

(0) is an expression of type signed int.
The value of (~0) is the result of a bitwise
operation that affects the sign bit.
Bitwise operations that affect the sign bit,
don't generally yield portable values.

((unsigned int)-1) is another right way to write UINT_MAX.

The result of only the most significant bit of the
unsigned int type being set, is:
(((unsigned int)-1 >> 1) + 1)
The next is:
(((unsigned int)-1 >> 2) + 1)
The next is:
(((unsigned int)-1 >> 3) + 1)
 
S

Skarmander

octangle said:
Create enumerated values using the three highest bits as bit flags that
define comparison operators.

VERSION A:
----------

enum eCriteria
{
eCriteriaOne = 1,
eCriteriaTwo = 2,
eCriteriaEtc = 9999,

eLess = 1 << ((sizeof(enum eCriteria) * 8) - 3),
eEqual = 1 << ((sizeof(enum eCriteria) * 8) - 2),
eGreater = 1 << ((sizeof(enum eCriteria) * 8) - 1),
}
Assumes CHAR_BIT is 8, and will not compile since the sizeof is applied to
an incomplete type.
VERSION B:
----------

enum eCriteria
{
eCriteriaOne = 1,
eCriteriaTwo = 2,
eCriteriaEtc = 9999,

eLess = ~(((unsigned int)(~0)) >> 1) >> 2,
eEqual = ~(((unsigned int)(~0)) >> 1) >> 1,
eGreater = ~(((unsigned int)(~0)) >> 1),
}
'~0' is the one's complement of all-bits-zero, that is, all-bits-one. The
value of this expression depends on the platform's representation of integers.
These bit flags are intended to be or'ed into other enumerated values
to indicate how these values are to participate in an underlying SQL
Select statement.
If these values intended to be stored in a table, you shouldn't be messing
around with "the high three bits" since it'll depend on your DB what values
can be stored. Pick an integer size and stick with it. And try not to use
these values in SQL queries; this will be really awkward. If possible, be
generous to yourself and use three BIT fields. You'll thank yourself later.
e.g.

{
/* <= Criteria 2 */

enum eCriteria lCriteria = eCriteriaTwo | eLess | eEqual;
}

Well, if you really want this, you should first settle for an integer type
to use. 'unsigned int' is probably a good choice. Then

#include <limits.h>

enum criterion {
criterion_1 = 1,
criterion_2 = 2,
/* ... */
criterion_less = (UINT_MAX >> 1) + 1,
criterion_equal = (UINT_MAX >> 2) + 1,
criterion_greater = (UINT_MAX >> 3) + 1
};

If you don't like UINT_MAX, you're free to use ((unsigned int) -1).

This is portable insofar as all platforms will use the "upper three bits"
for the comparison flags, but obviously the values so obtained are not
portable between platforms with different integer sizes, and you should not
store these values in a database (if you're going to assume integers are a
certain size, you may as well spell out the constants).

S.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top