sizeof suggestion

S

sandeep

Hello

A serious limitation of C is that the sizeof operator can't be applied to
expressions of bitfield type. I would recommend extending sizeof to
bitfields for the sake of consistency and potential usefulness (the "why
not" principle).

Note that multiples of 1/8 can be expressed exactly in floating-point, so
it would make sense for sizeof to return a size_t for expressions not
involving bitfields, and a float when applied to bitfields.
 
E

Eric Sosman

Hello

A serious limitation of C is that the sizeof operator can't be applied to
expressions of bitfield type. I would recommend extending sizeof to
bitfields for the sake of consistency and potential usefulness (the "why
not" principle).

Note that multiples of 1/8 can be expressed exactly in floating-point, so

Where did this magic "1/8" come from?
it would make sense for sizeof to return a size_t for expressions not
involving bitfields, and a float when applied to bitfields.

Suppose for a moment that sizeof behaved as you suggest. Now,
the crucial question: Having learned that some datum has a size of
2.375 bytes, what use will you make of the information? Will you
malloc() a memory area of two-and-a-fraction bytes to hold it? Will
you read two-and-a-fraction bytes from a file to fill it? Will you
memcpy() 15*2.375 = not quite 36 bytes to move a batch of them from
one place to another? Will you extend pointer arithmetic to handle
pointer plus-or-minus float?

In short, what does this "serious limitation" prevent you from
accomplishing?
 
B

Ben Bacarisse

sandeep said:
A serious limitation of C is that the sizeof operator can't be applied to
expressions of bitfield type. I would recommend extending sizeof to
bitfields for the sake of consistency and potential usefulness (the "why
not" principle).

I think you've lost track of your logic. If it's a "serious limitation"
it should be covered by something much stronger than some "why not"
principle.

What program were you writing when you hit this serious limitation?
Someone here might be able to offer a work-around.
Note that multiples of 1/8 can be expressed exactly in floating-point,

That's not guaranteed by the C standard, though it is highly likely.
so
it would make sense for sizeof to return a size_t for expressions not
involving bitfields, and a float when applied to bitfields.

A floating result would preclude implementing C on machines with 9-bit
bytes unless the floating point arithmetic were similarly peculiar.
 
S

sandeep

Eric said:
Where did this magic "1/8" come from?

There are 8 bits in a byte. So any number of bits is a multiple of 1/8
byte.
Suppose for a moment that sizeof behaved as you suggest. Now,
the crucial question: Having learned that some datum has a size of 2.375
bytes, what use will you make of the information? Will you malloc() a
memory area of two-and-a-fraction bytes to hold it? Will you read
two-and-a-fraction bytes from a file to fill it? Will you memcpy()
15*2.375 = not quite 36 bytes to move a batch of them from one place to
another? Will you extend pointer arithmetic to handle pointer
plus-or-minus float?

In short, what does this "serious limitation" prevent you from
accomplishing?

I expect there are lots of things that people would find to do with it.

One simple example is avoiding overflows when setting a bitfield: you
could have code like

s.x = newval & ~((INT_MAX >> (8 * sizeof(s.x))) << (8 * sizeof(s.x)));

For example, if sizeof(s.x) was 3/8, then this would become

s.x = newval & 07;

and the assignment would never overflow.
 
B

BartC

sandeep said:
Hello

A serious limitation of C is that the sizeof operator can't be applied to
expressions of bitfield type. I would recommend extending sizeof to
bitfields for the sake of consistency and potential usefulness (the "why
not" principle).

Better to return a size in bits.

But to avoid confusion, it might also be better to use a slightly
differently named operator to sizeof, eg. "bitsizeof". Then it can also be
applied to any type, more conveniently than now. (And while we're about it,
'elementsof' would come in handy too, for arrays.)

BTW I'm not sure bitfield expressions /have/ their own type, I think they
are just widened to ints.
 
E

Eric Sosman

There are 8 bits in a byte. So any number of bits is a multiple of 1/8
byte.

There are *at least* eight bits in a byte.
I expect there are lots of things that people would find to do with it.

One simple example is avoiding overflows when setting a bitfield: you
could have code like

s.x = newval& ~((INT_MAX>> (8 * sizeof(s.x)))<< (8 * sizeof(s.x)));

Left- and right-shifting by a floating-point number of bits?
For example, if sizeof(s.x) was 3/8, then this would become

s.x = newval& 07;

At best it might be `s.x = newval & 7.0f;', so now you're also
defining the & (and presumably |,^) operators for floating-point
operands?
and the assignment would never overflow.

<Shrug.> In the cases where it might have overflowed, it now
gets the wrong answer silently. (It also gets the wrong answer for
negative values that wouldn't have overflowed at all.) Doesn't
strike me as an improvement worth having, but YMMV.

Allow me to suggest a small experiment: Get the source of gcc,
change it to support the various extensions you describe, publish
the result, and see how well it's received. If you are right in
calling size-less bit-fields a "serious limitation" and if you are
right that there are "lots of things" people would like to do with
fractional bit-counts, your innovation will gain a grateful following
*and* there will be prior art to support a proposal for a future C
Standard. Give it a try, okay?
 
I

Ian Collins

I expect there are lots of things that people would find to do with it.

One simple example is avoiding overflows when setting a bitfield: you
could have code like

s.x = newval& ~((INT_MAX>> (8 * sizeof(s.x)))<< (8 * sizeof(s.x)));

For example, if sizeof(s.x) was 3/8, then this would become

s.x = newval& 07;

and the assignment would never overflow.

In addition to Eric's reply, in my experience bit fields are seldom used
as restricted size ints. They are more often used to represent entities
define by a fixed set of constants. Even when they are used for small,
fixed sized ints their values are read and written by code that knows
their size.
 
P

Peter Nilsson

BartC said:
... BTW I'm not sure bitfield expressions /have/ their
own type, I think they are just widened to ints.

The type of a bitfield member is its base type. The range
is limited by its width.
 
T

Tim Rentsch

Peter Nilsson said:
The type of a bitfield member is its base type. The range
is limited by its width.

No, the type of a bitfield is a distinct type from its
base type (assuming the bitfield's width is less than
the width of the base type). The types have to be
different to make the integer conversion rules work
right -- if the type of a 4-bit 'unsigned' bitfield
were just 'unsigned', then adding -37 to such a bitfield
would yield an unsigned result, which isn't what happens.
Conversion rules are defined solely in terms of type,
not "type plus range limitation".
 
E

Eric Sosman

No, the type of a bitfield is a distinct type from its
base type (assuming the bitfield's width is less than
the width of the base type). The types have to be
different to make the integer conversion rules work
right -- if the type of a 4-bit 'unsigned' bitfield
were just 'unsigned', then adding -37 to such a bitfield
would yield an unsigned result, which isn't what happens.
Conversion rules are defined solely in terms of type,
not "type plus range limitation".

Can you cite the Standard section(s) supporting your claim?
When BartC posted his remark I went looking for text that would
reassure him that bit-fields had width-influenced types, but (to
my surprise) didn't find anything. The only direct references
I found to types of bit-fields were 6.3.1.1p2 and 6.7.2.1p4, both
of which appear to support Peter Nilsson's statement.
 
B

BartC

Can you cite the Standard section(s) supporting your claim?
When BartC posted his remark I went looking for text that would
reassure him that bit-fields had width-influenced types, but (to
my surprise) didn't find anything.

I was only referring to the promotions that might occur for bitfield
/expressions/, as they do here for char types:

char c;

printf("sizeof (char) = %d\n",sizeof(char));
printf("sizeof (c) = %d\n",sizeof(c));
printf("sizeof (c+1) = %d\n",sizeof(c+1));

My machine gives me 1, 1, and 4. So c+1 is an expression, but c on it's own
isn't.

In a similar way, a bitfield expression might give the number of chars in
the underlying int type, rather than the number of bits, or number of
fractional bytes as the OP proposed (which, for a mixed bitfield expression,
is not so easy to determine).
 
B

BruceS

In addition to Eric's reply, in my experience bit fields are seldom used
as restricted size ints.  They are more often used to represent entities
define by a fixed set of constants.  Even when they are used for small,
fixed sized ints their values are read and written by code that knows
their size.

The system I most frequently use has these. It was designed back when
it made sense to save a few bits here, a few there, so there are
integer fields with sizes :4, :6, and :7. Having said that, I should
also say that the code reads entire structures at a time, and those
(for equally old reasons) are padded to 8-byte (8-bit bytes)
boundaries. Not that any of this lends any validity to the OP's
premise, but some of us do have to work with these sub-byte integers
on a regular basis. I guess that just makes my work unusual, so the
"seldom" applies.
 
K

Keith Thompson

BartC said:
I was only referring to the promotions that might occur for bitfield
/expressions/, as they do here for char types:

char c;

printf("sizeof (char) = %d\n",sizeof(char));
printf("sizeof (c) = %d\n",sizeof(c));
printf("sizeof (c+1) = %d\n",sizeof(c+1));

My machine gives me 1, 1, and 4. So c+1 is an expression, but c on it's own
isn't.

You misunderstand.

Both c and c+1 are expressions. They just happen to be of different
types (which is admittedly a bit counterintuitive). The "+" operator
applies the "usual arithmetic conversions" to its arguments, which is
why c+1 is of type int (or conceivably unsigned int in some exotic
implementations). sizeof does not apply the usual arithmetic
conversions to its arguments, so sizeof applied to an expression of type
char yields 1.

Note that sizeof's argument doesn't need parentheses if it's an
expression (though you can certainly give it a parenthesized
expression). Note also that "%d" requires an int argument, not
a size_t argument. So I'd write the above as:

char c;

printf("sizeof (char) = %d\n", (int)sizeof (char) );
printf("sizeof c = %d\n", (int)sizeof c);
printf("sizeof (c+1) = %d\n", (int)sizeof (c+1));

Note that you still need parentheses in "sizeof (c+1)", but only for
grouping, not because sizeof needs them. Without the parentheses,
"sizeof c+1" means "(sizeof c) + 1".

[...]
 
L

lawrence.jones

Eric Sosman said:
Can you cite the Standard section(s) supporting your claim?
[that the width of a bit-field is part of its type]

6.7.2.1p10:

A bit-field is interpreted as a signed or unsigned integer type
consisting of the specified number of bits.
 
P

Peter Nilsson

Eric Sosman said:
Can you cite the Standard section(s) supporting your claim?

[that the width of a bit-field is part of its type]

6.7.2.1p10:

        A bit-field is interpreted as a signed or unsigned
integer type consisting of the specified number of
bits.

Then why does 6.2.7p1 say that for structs and unions to be
compatible, corresponding bitfields must have compatible
type *and* width? How does one typedef a compatible type for
a bitfield if width is a part of the type?
 
E

Eric Sosman

[...]
I was only referring to the promotions that might occur for bitfield
/expressions/, as they do here for char types:

char c;

printf("sizeof (char) = %d\n",sizeof(char));
printf("sizeof (c) = %d\n",sizeof(c));
printf("sizeof (c+1) = %d\n",sizeof(c+1));

My machine gives me 1, 1, and 4. So c+1 is an expression, but c on it's own
isn't.

Except that it is. Trace through the grammar: The very first
production of "primary-expression" (in 6.5.1) is "identifier". Also,
the sizeof operator (6.5.3) can be applied to "( type-name )" or to
"unary-expression" -- unless you maintain that c is a "type-name"
(in which case you'd have to accept "c x;" as a valid declaration),
you're stuck with it as a "unary-expression".
 
E

Eric Sosman

Eric Sosman said:
Can you cite the Standard section(s) supporting your claim?
[that the width of a bit-field is part of its type]

6.7.2.1p10:

A bit-field is interpreted as a signed or unsigned integer type
consisting of the specified number of bits.

... so the "type" is one of the signed or unsigned integers.
It comes down to whether "consisting of" binds more or less tightly
than "is interpreted as:"

bit-field is interpreted as (a signed or unsigned ... of
the specified number of bits) -> Rentsch

(bit-field is interpreted as a signed or unsigned ...)
consisting of the specified number of bits -> Nilsson

I note, with my eyebrow archly arched, the absence of any mention
of bit-field widths in the exposition of conversion ranks. ;-)

(FWIW, gcc agrees with Rentsch -- which only goes to show that
there are earnest people on both sides of the question.)
 
T

Tim Rentsch

Peter Nilsson said:
Eric Sosman said:
Can you cite the Standard section(s) supporting your claim?

[that the width of a bit-field is part of its type]

6.7.2.1p10:

A bit-field is interpreted as a signed or unsigned
integer type consisting of the specified number of
bits.

Then why does 6.2.7p1 say that for structs and unions to be
compatible, corresponding bitfields must have compatible
type *and* width?

Actually what it says is slightly different, namely, that
corresponding members are /declared/ with compatible types. The
width of a bitfield serves to modify the /declared type/ so as to
define the /access type/ for the bitfield. Unfortunately the
Standard is not always as clear as it could be in distinguishing
these two uses of "type" in relation to bitfields. (The Standard
is better about that in other cases, notably the treatment of
array types for function parameters, for example.)

How does one typedef a compatible type for
a bitfield if width is a part of the type?

No way (without some sort of extensions) to write such a
typedef, but it's only the declared types that have to
be compatible (with a separate statement that the widths
must be equal). Having both statements is important for
implementations that allow bitfields for other integer
types. For example, given two struct definitions in
different translation units:

struct A { int foo:5; };

struct A { long foo:5; };

even though the access types for the two bitfields may be
the same, the two struct types are not compatible, because
the bitfield members' declared types are not compatible.
 
T

Tim Rentsch

Eric Sosman said:
Eric Sosman said:
Can you cite the Standard section(s) supporting your claim?
[that the width of a bit-field is part of its type]

6.7.2.1p10:

A bit-field is interpreted as a signed or unsigned integer type
consisting of the specified number of bits.

... so the "type" is one of the signed or unsigned integers.
It comes down to whether "consisting of" binds more or less tightly
than "is interpreted as:"

bit-field is interpreted as (a signed or unsigned ... of
the specified number of bits) -> Rentsch

(bit-field is interpreted as a signed or unsigned ...)
consisting of the specified number of bits -> Nilsson

I note, with my eyebrow archly arched, the absence of any mention
of bit-field widths in the exposition of conversion ranks. ;-)

They aren't mentioned explicitly, but are relevant because of the
second list item in 6.3.1.1p1 (unsigned types are covered by another
item in the same list):

The rank of a signed integer type shall be greater than the
rank of any signed integer type with less precision.

For integer types, 'precision' and 'width' are related -- knowing
one determines the other. In case there is any doubt that the size
of a bit-field is its width, there is this sentence in 6.2.6.1p4:

Values stored in bit-fields consist of m bits, where m is
the size specified for the bit-field.

So the width of a bit-field definitely affects its conversion rank.

(FWIW, gcc agrees with Rentsch -- which only goes to show that
there are earnest people on both sides of the question.)

I suspect the confusion arises because the Standard sometimes
refers to the type of a bit-field to mean the declared type of
the bit-field member rather than the access type for the
corresponding bit-field object. For most identifiers the
declared type and the access type are the same, and when they are
not (as happens with some function parameters) it's important to
distinguish the two; unfortunately the Standard isn't always good
about distinguishing these clearly when talking about bit-fields.

Does anyone know of any compiler that gives a result different from
what gcc gives in this regard?
 

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,764
Messages
2,569,564
Members
45,040
Latest member
papereejit

Latest Threads

Top