Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparison of a bitfield vs a (negative) integer, undefined behavior or compiler bugs?

Tags:

c

Here is a small program. Should this print 0 or 1, or does it have undefined behavior ?

#include <stdio.h>
struct S0 {
  unsigned f1 : 1;
};

struct S0 s;

int main (void) {
  int x = -3;
  int y = x >= (0, s.f1);
  printf ("%d\n", y);
  return 0;
}

This is taken from a resent CSmith test, and this case is discussed more here .

In particular, GCC, KCC, and CompCert outputs 0, while MSVC 2010, ICC 12.0.2 and recent Clang outputs 1.

like image 455
Lyke Avatar asked Jul 14 '11 14:07

Lyke


People also ask

What is Bitfield C++?

Both C and C++ allow integer members to be stored into memory spaces smaller than the compiler would ordinarily allow. These space-saving structure members are called bit fields, and their width in bits can be explicitly declared.

What is a bit-field used for?

Bit fields can be used to reduce memory consumption when a program requires a number of integer variables which always will have low values. For example, in many systems storing an integer value requires two bytes (16-bits) of memory; sometimes the values to be stored actually need only one or two bits.

Can we reference a bit-field?

Pointers and non-const references to bit-fields are not possible. When initializing a const reference from a bit-field, a temporary is created (its type is the type of the bit-field), copy initialized with the value of the bit-field, and the reference is bound to that temporary.


1 Answers

Interesting question.

According to the C99 draft standard 6.5.17.1, the type of (0, s.f1) is the same as that of s.f1, which (per 6.7.2.1.9) is "an unsigned integer type consisting of 1 bit". This is an arithmetic type by virtue of being an integer type, its precision is 1 (per 6.2.6.2.6, and 6.2.6.1.3 implies no padding bits), and therefore its rank is less than that of int (per the second item under 6.3.1.1.1; int has a precision of at least 15, since it must be able to represent values in the range -32767 to 32767 (see 5.2.4.2.1)).

Since both x and the expression (0, s.f1) have arithmetic type, the usual arithmetic conversions are performed (per 6.5.8.3). Since an int can represent the full range of values of s.f1, it is promoted to a (signed) int (per 6.3.1.1.2). Then since both operands are (signed) ints, the common real type is signed int (per 6.3.1.8) and therefore the result of the comparison should be 0.

like image 112
Anomie Avatar answered Sep 21 '22 06:09

Anomie