Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are bit flags using ints in C/C++ actually safe?

Tags:

c++

c

I've noticed that many C/C++ programmers implement sets of flags using something like the following:

#define FLAG_1 (1 << 0)
#define FLAG_2 (1 << 1)
#define FLAG_3 (1 << 2)

unsigned int my_flags = 0; /* no flag set */
my_flags |= FLAG_2; /* set flag 2 */

But is this approach actually sound? It seems to me like it's making assumptions about the binary representation of unsigned ints that isn't part of the C/C++ language standard. For example, that "0" is actually 0x0000.

Am I wrong? Or am I right in theory, but not in practice given currently standard hardware?

like image 235
Christian Convey Avatar asked Oct 02 '12 18:10

Christian Convey


People also ask

What is a bit flag in C?

In programming languages like C or C++, Bit Flags are used to store more than one boolean value in one byte or a whole set of bytes. Usually, they are represented as binary.

Why use Bitwise operators in C?

For handling electronics and IoT-related operations, programmers use bitwise operators. It can operate faster at a bit level. The Bitwise Operator in C performs its operation on the individual bits of its operand, where operands are values or expressions on which an operator operates.

Why do we use flag in C?

Flag variable is used as a signal in programming to let the program know that a certain condition has met. It usually acts as a boolean variable indicating a condition to be either true or false.

What is the minimum size of binary flag variable in C?

This set of states only requires one bit to store. However, if a variable must be at least a byte, and a byte is 8 bits, that means a Boolean is using 1 bit and leaving the other 7 unused.


2 Answers

C++

The important part of the C++11 standard is §3.9.1/7 (ISO/IEC 14882:2011(E)):

The representations of integral types shall define values by use of a pure binary numeration system.

This is clarified in a footnote:

49) A positional representation for integers that uses the binary digits 0 and 1, in which the values represented by successive bits are additive, begin with 1, and are multiplied by successive integral power of 2, except perhaps for the bit with the highest position. (Adapted from the American National Dictionary for Information Processing Systems.)

The results of shift operators are defined mathematically. For example, for E1 << E2:

If E1 has an unsigned type, the value of the result is E1 × 2E2 , reduced modulo one more than the maximum value representable in the result type. Otherwise, if E1 has a signed type and non-negative value, and E1 × 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.

The bitwise operators are specifically defined as being bitwise. For example, for bitwise OR:

The usual arithmetic conversions are performed; the result is the bitwise exclusive OR function of the operands.

Of course, under the as-if rule, the representation does not truly have to be the pure binary numeration system. The compiler must only produce a program that acts as if it were.

C

In C99 (ISO/IEC 9899:TC3), pure binary notation is only guaranteed for bit-fields and objects of type unsigned char (§6.2.6.1/3):

Values stored in unsigned bit-fields and objects of type unsigned char shall be represented using a pure binary notation.

Again clarified in a footnote:

A positional representation for integers that uses the binary digits 0 and 1, in which the values represented by successive bits are additive, begin with 1, and are multiplied by successive integral powers of 2, except perhaps the bit with the highest position. (Adapted from the American National Dictionary for Information Processing Systems.)

The standard specifically points out that bitwise operations depend on the internal representation (§6.5/4):

Some operators (the unary operator ~, and the binary operators <<, >>, &, ^, and |, collectively described as bitwise operators) are required to have operands that have integer type. These operators yield values that depend on the internal representations of integers, and have implementation-defined and undefined aspects for signed types.

like image 180
Joseph Mansfield Avatar answered Sep 23 '22 20:09

Joseph Mansfield


While it's theoretically possible to run C or C++ on an architecture that uses non-power-of-2 arithmetic, the |, &, and ^ operators are defined to have bitwise behavior, so such a machine would need to emulate binary arithmetic.

It's therefore completely safe and portable.

like image 30
Ben Voigt Avatar answered Sep 24 '22 20:09

Ben Voigt