Re: GLogLevelFlags enum and g_log

On 28/05/14 21:52, Jonathan S. Shapiro wrote:
So in both cases an enum can be smaller than an int according to
implementation-defined criteria. The more substantive difference is that
in C++ an enum can be /larger/ than an int.

The text you quoted doesn't seem to imply that enums can't be larger
than int in C either.

However, there is something more fundamental here: does GLib aim to be
portable to arbitrary ISO C platforms (including oddities like 36-bit
bytes or sign&magnitude arithmetic), or to the narrower set of platforms
that people actually use in the real world?

If the former, language lawyering about sizes of enums is appropriate.

If the latter, we can add a static assertion that sizeof (small enum) ==
sizeof (int) and get on with our lives, and worry about what the
standard says if we find a real, relevant platform where the static
assertion fails.

In practice, I suspect that in relevant compilers, all enums whose
values fit in the range INT32_MIN to INT32_MAX (inclusive) are the same
size as int. ISO C allows compiler to break that assumption, but those
that do would break code that works fine in other compilers, making the
compiler look bad, for no significant benefit. I conjecture that such
compilers are not popular.

In practice, the "smaller than int" issue isn't a concern at parameter
passing, where parameters are widened to a full machine word in any

More precisely, ISO C's "usual promotions" guarantee to widen
smaller-than-int parameters to int.

Then there are structure alignment and offset assumptions.
I don't see (offhand) what value the static assertion about
enumeration size is giving us in regards to this issue

It doesn't solve anything in that respect; if people assume "
starts 8 bytes after the start of Foo" (or whatever) then they should be
replacing that assumption with uses of sizeof(), G_STRUCT_OFFSET() and
something analogous to alignof(); or at the very least, adding a
G_STATIC_ASSERT (G_STRUCT_OFFSET (Foo, bar) == 8) as executable
documentation of their assumption.

For compatibility with compilers with poor C support like MSVC, GLib is
written in C89, which doesn't have alignof() and offsetof() - but it
does have G_STRUCT_OFFSET(), and code internal to GLib can use
_g_alignof() to get an equivalent of alignof(). I didn't make it public
API because I only needed it internally for static assertions, I wasn't
sure that it was 100% portable.

By suggesting that static assertion, I was only trying to solve enum
extension. "When I make this reasonable-looking change between libfoo 2
and libfoo 2, I don't want it to be an ABI break" is quite important to
anyone who cares about ABI.

Next there are "unholy overlays", by which I mean places where somebody
has tucked items of unspecified size and alignment into a union from
which they try to re-extract them using some other "leg" of the union.
THAT's just bad code, and it needs to be fixed as we find it.

Unions solve alignment, in fact (the union is as strictly-aligned as its
most strictly-aligned member), although you still need to worry about
size when using type-punning.

Meanwhile, there is a preemptive way to /force/ the compiler to choose
"at least int" as the enum size:

enum GLogLevel {
   ... existing, expected values ...
   _require_int = INT_MAX

This works because the compiler is now required to choose an underlying
integral type that will hold INT_MAX. The problem with doing this is
that it will break ABI compatibility on any platform that
/currently/ encodes GLogLevel as a char. I'm actually not aware of any
compiler that does this, but it would probably be a good idea to check
before making this change and accidentally breaking things.

The static assertion would trip on exactly those platforms.

My suggestion: just add the static assertion and see what happens. If it
succeeds on all relevant platforms, no harm done. My intuition is that
this is what will happen, because real-world CPUs get performance
benefits from only dereferencing word-aligned pointers, and a
substantial amount of real-world code blindly assumes int-sized enums,
so there is selection pressure on compilers to make enums consistently
int-sized if they could have been smaller than int.

If it fails on some platform, then the GLib maintainers have to choose
whether breaking ABI on that platform now is a worthwhile sacrifice to
be able to add enum members without breaking ABI in future.


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]