Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Why sizeof(bitfield) gives wrong result ?

288 views
Skip to first unread message

Jean Fan

unread,
Nov 1, 1999, 3:00:00 AM11/1/99
to
Hi everyone, I'm new to the list, so excuse me if this
issue is already known and treated.

My pb concerns the sizeof of a bitfield struct, all
work fine with Borland C++ (4.52), we are moving recently
to VC++ 6, and are finding strange things with this one,
for exemple:

typedef struct
{
BYTE a : 1 ;
BYTE b : 1 ;
BYTE c : 7 ;
BYTE d : 7 ;
} my_bitf ;

With VC++6, sizeof(my_bitf) give 3 and not 2 as we expected.
We think this should be a bug in VC++, and we've send a bug report
to Microsoft, 2 weeks passed, silence...

--
Jean


Phlip

unread,
Nov 1, 1999, 3:00:00 AM11/1/99
to
Jean Fan wrote:

BYTE is a 'unsigned char'. That means bits are padded out to 'char'
boundaries if they don't all fit in one.

typedef struct


BYTE a : 1 ; <-- fits in first char
BYTE b : 1 ; <-- fits in first char
BYTE c : 7 ; <-- first char would be 9 bits - moved to second
char
BYTE d : 7 ; <-- second char would be 14 bits - moved to third
char
} my_bitf ;

All this behavior has been defined for years by the Standards for
the C languages. MS's "silence" can be interpreted as "RTFM".

The fix is to make BYTE into an 'unsigned short' or 'WORD'. That
would let many bits fit in one 16-bit object, which is what you
need.

--
Phlip at politizen dot com (address munged)
======= http://users.deltanet.com/~tegan/home.html =======
-- The first few lines of code must "hook" the
computer, and make it "care" about the program --

Andreas Arff

unread,
Nov 1, 1999, 3:00:00 AM11/1/99
to
I don't think it's a bug. VC doesn't allow you to split
a bitfield across byte boundaries (or something like that).
So what happens is that c uses a 2nd byte and d uses a 3rd.
I remember reading something about this behavior somewhere
in MSDN several years back. Check there for more information.

Andreas

Jean Fan wrote:
>
> Hi everyone, I'm new to the list, so excuse me if this
> issue is already known and treated.
>
> My pb concerns the sizeof of a bitfield struct, all
> work fine with Borland C++ (4.52), we are moving recently
> to VC++ 6, and are finding strange things with this one,
> for exemple:
>
> typedef struct
> {
> BYTE a : 1 ;
> BYTE b : 1 ;
> BYTE c : 7 ;
> BYTE d : 7 ;
> } my_bitf ;
>
> With VC++6, sizeof(my_bitf) give 3 and not 2 as we expected.
> We think this should be a bug in VC++, and we've send a bug report
> to Microsoft, 2 weeks passed, silence...
>

> --
> Jean

Mathew Hendry

unread,
Nov 1, 1999, 3:00:00 AM11/1/99
to
"Phlip" <new_...@see.web.page> wrote:

: Jean Fan wrote:
:
: > typedef struct


: > {
: > BYTE a : 1 ;
: > BYTE b : 1 ;
: > BYTE c : 7 ;
: > BYTE d : 7 ;
: > } my_bitf ;
: >
: > With VC++6, sizeof(my_bitf) give 3 and not 2 as we expected.
: > We think this should be a bug in VC++, and we've send a bug report
: > to Microsoft, 2 weeks passed, silence...

:
: BYTE is a 'unsigned char'. That means bits are padded out to 'char'


: boundaries if they don't all fit in one.

: ...
: All this behavior has been defined for years by the Standards for


: the C languages. MS's "silence" can be interpreted as "RTFM".

TFM (i.e. the ISO standard) says very little about how bitfields
should be laid out. Each field could require 200K, or there might be
no padding at all. IIRC, the fields needn't even appear in lexical
order. Also, unsigned char isn't a valid type for a bitfield anyway -
VC supports that as an extension. (/W4 will warn about it).

--

Mathew Hendry, Programmer, Visual Sciences Ltd.
Work <ma...@vissci.com>, Home <sca...@dial.pipex.com>
IRC/ICQ/Q2/... "Scampi", ICQ 24839718
PGP B3C1 1EBC 2BAE 93F0 54C1 E0E7 5FA3 5988 BBD6 B689

J. Wesley Cleveland

unread,
Nov 1, 1999, 3:00:00 AM11/1/99
to

Jean Fan wrote:
>
> Hi everyone, I'm new to the list, so excuse me if this
> issue is already known and treated.
>
> My pb concerns the sizeof of a bitfield struct, all
> work fine with Borland C++ (4.52), we are moving recently
> to VC++ 6, and are finding strange things with this one,
> for exemple:
>

> typedef struct
> {
> BYTE a : 1 ;
> BYTE b : 1 ;
> BYTE c : 7 ;
> BYTE d : 7 ;
> } my_bitf ;
>
> With VC++6, sizeof(my_bitf) give 3 and not 2 as we expected.
> We think this should be a bug in VC++, and we've send a bug report
> to Microsoft, 2 weeks passed, silence...

Bitfields are implementation-dependent and highly non-portable. If you
upgraded to BC5, I suspect your code would also not work. I would
recommend not using them.

Jean Fan

unread,
Nov 1, 1999, 3:00:00 AM11/1/99
to
Phlip wrote :

> BYTE is a 'unsigned char'. That means bits are padded out to 'char'
> boundaries if they don't all fit in one.
> All this behavior has been defined for years by the Standards for
> the C languages. MS's "silence" can be interpreted as "RTFM".
> The fix is to make BYTE into an 'unsigned short' or 'WORD'. That
> would let many bits fit in one 16-bit object, which is what you
> need.

Thanks a lot, it works with WORD.
But I don't understand why it dosen't work with BYTE,
your explication is not very clear for me.

J. Wesley Cleveland wrote


> Bitfields are implementation-dependent and highly non-portable. If you
> upgraded to BC5, I suspect your code would also not work. I would
> recommend not using them.

With BC5, no problem, sizeof(my_bitf) = 2 !

For me, the behavior in VC, if it's not a bug, it's in any way
not expected regarding the following text extracted from the official
MSDN in VC6 (C Bit Fields), see especially the example in the end,
excuse me for the long text.

Would you always say it's not a bug ?

***************************************************** Extracted from VC
6 MSDN
C Bit Fields
In addition to declarators for members of a structure or union,
a structure declarator can also be a specified number of bits,
called a bit field. Its length is set off from the declarator
for the field name by a colon. A bit field is interpreted as an
integral type.

Syntax
struct-declarator :
declarator
type-specifier declarator opt : constant-expression

The constant-expression specifies the width of the field in bits.
The type-specifier for the declarator must be unsigned int, signed int,
or int, and the constant-expression must be a nonnegative integer value.
If the value is zero, the declaration has no declarator.
Arrays of bit fields, pointers to bit fields, and functions returning
bit fields are not allowed. The optional declarator names the bit field.
Bit fields can only be declared as part of a structure. The address-of
operator (&) cannot be applied to bit-field components.

Unnamed bit fields cannot be referenced, and their contents at run time
are unpredictable. They can be used as dummy fields, for alignment
purposes.
An unnamed bit field whose width is specified as 0 guarantees that
storage
for the member following it in the struct-declaration-list begins on an
int boundary.

Bit fields must also be long enough to contain the bit pattern.
For example, these two statements are not legal:

short a:17; /* Illegal! */
int long y:33; /* Illegal! */

This example defines a two-dimensional array of structures named screen.

struct
{
unsigned short icon : 8;
unsigned short color : 4;
unsigned short underline : 1;
unsigned short blink : 1;
} screen[25][80];

The array contains 2,000 elements. Each element is an individual
structure
containing four bit-field members: icon, color, underline, and blink.
The size of each structure is two bytes.

Bit fields have the same semantics as the integer type.
This means a bit field is used in expressions in exactly the same way as
a
variable of the same base type would be used, regardless of how many
bits
are in the bit field.

Microsoft Specific :
Bit fields defined as int are treated as signed. A Microsoft extension
to the
ANSI C standard allows char and long types (both signed and unsigned)
for bit
fields. Unnamed bit fields with base type long, short, or char (signed
or unsigned)
force alignment to a boundary appropriate to the base type.

Bit fields are allocated within an integer from least-significant to
most-significant bit. In the following code

struct mybitfields
{
unsigned short a : 4;
unsigned short b : 5;
unsigned short c : 7;
} test;

void main( void );
{
test.a = 2;
test.b = 31;
test.c = 0;
}

the bits would be arranged as follows:

00000001 11110010
cccccccb bbbbaaaa

Since the 8086 family of processors stores the low byte of integer
values before the high byte, the integer 0x01F2 above would be stored
in physical memory as 0xF2 followed by 0x01.

END Microsoft Specific
*************************************************** END Extracted from
VC 6 MSDN

--
Jean
____________________________________________________
Nous apprenons la geologie le matin apres le seisme.
--
Lao FAN
____________________________________________________
Nous apprenons la geologie le matin apres le seisme.

Erik Funkenbusch

unread,
Nov 1, 1999, 3:00:00 AM11/1/99
to
Jean Fan <xiao.ga...@libertysurf.fr> wrote in message
news:381E0661...@libertysurf.fr...

> Thanks a lot, it works with WORD.
> But I don't understand why it dosen't work with BYTE,
> your explication is not very clear for me.

Yes, because all your bits can fit within a WORD. They can't all fit
within a BYTE.

using BYTE: the storage would look like this

BYTE a : 1; // storage now looks like this 00000001

BYTE b : 1; // storage now looks like this 00000011 (notice that
there are only 6 unused bits left in the BYTE)

BYTE c : 7; // 7 is to large to fit within the remaining 6 bits, and
since bitfields cannot span multiple storage types, it moves it to the
next BYTE 01111111 (note only 1 remaining bit)

BYTE d : 7; // Again, since there is only one remaining bit, it moves
it to the third BYTE.

If you want to optimize this, you should declare them as:

BYTE a : 1; // storage now looks like this 00000001 (note 7
remaining bits)
BYTE c : 7; // 7 is large enough to fit into the remaining bits of
byte 1, so it still takes 1 byte
BYTE b : 1; // 1 bit allocated in byte 2
BYTE d : 7; // 7 is large enough to fit into the remaining bits of
byte 2, so all 4 fields take 2 bytes

> With BC5, no problem, sizeof(my_bitf) = 2 !

you're defining it the same way?

> For me, the behavior in VC, if it's not a bug, it's in any way
> not expected regarding the following text extracted from the
official
> MSDN in VC6 (C Bit Fields), see especially the example in the end,
> excuse me for the long text.

The text show specifically how this works. (see below)

> Would you always say it's not a bug ?

No.


> short a:17; /* Illegal! */

This shows that bitfields cannot span multiple storage types.

> struct
> {
> unsigned short icon : 8;
> unsigned short color : 4;
> unsigned short underline : 1;
> unsigned short blink : 1;
> } screen[25][80];

They all fit in one short, since a short is one storage type and all
the bits add up to less than one type. No boundaries are crossed.

perhaps you can point to the specific paragraph which you think
contradicts this.

Doug Harrison

unread,
Nov 1, 1999, 3:00:00 AM11/1/99
to
Jean Fan wrote:

>Hi everyone, I'm new to the list, so excuse me if this
>issue is already known and treated.
>
>My pb concerns the sizeof of a bitfield struct, all
>work fine with Borland C++ (4.52), we are moving recently
>to VC++ 6, and are finding strange things with this one,
>for exemple:
>
>typedef struct
>{
> BYTE a : 1 ;
> BYTE b : 1 ;
> BYTE c : 7 ;
> BYTE d : 7 ;
>} my_bitf ;
>
>With VC++6, sizeof(my_bitf) give 3 and not 2 as we expected.
>We think this should be a bug in VC++, and we've send a bug report
>to Microsoft, 2 weeks passed, silence...

In general, you won't get a reply to a bug report filed via the web form at:

http://support.microsoft.com/support/visualc/report/default.asp

They'll look at it, but you won't get any confirmation. You might want to
use one of your free support incidents, if this is important enough to you.
See Help->Technical Support for more.

But this is not a bug. Much bitfield behavior is implementation-defined, and
above, you're expecting that bitfields can cross storage boundaries. While a
and b can fit in a BYTE, c cannot fit in that same BYTE, so c is stored in a
separate byte. Ditto for d. This is fine by the C and C++ standards, and
this explains why sizeo(my_bitf) is 3 in VC++. You should be able to work
around this problem by declaring all the members as unsigned short int.

--
Doug Harrison
dHar...@worldnet.att.net
Visual C++ MVP


Jean Fan

unread,
Nov 2, 1999, 3:00:00 AM11/2/99
to
Hi,
Thanks to all who have taken time to reply my
question about the pb with sizeof(bitfields) in VC.

After reading carefully the answers, I want to conclude
that the pb I've experienced is not a bug in VC,
but it's due to a fundamental difference between BC and VC
in the implementation of bitfields structure.

--------------------------------------------------------------
In BC, the type (char, BYTE, short, int, ...)
of the bit fields in a structure dosen't affect
the storage allocation scheme of the structure :
the bits mapping the first field to the last field
are simply arranged from position 0 to n-1,
where n is the sum of the width of all bitfields
in the structure.
So there's no consideration of "boundary alignment" AND
you can mix different types of bitfields in a
structure without any problem.
No surprise : the size of the structure = n/8 + (n%8)?1:0.

For me, this is a very clear, direct and logical
implementation for bitfields, anyone can understand it !
More, it's relatively portable : the passage of 16 bits
=> 32 bits or 32 bits => 64 bits don't change anything
to the memory scheme.
--------------------------------------------------------------
In VC, it's another story.
The logic would to say that a bitfield structure is based
on an "underlying type", which is the greatest size type
of all the bit fields defined in the structure, AND there
will be a "boundary alignment" of the fields on this
underlying type.

A very strange logic for me. I don't love it at all !

I want to point 2 defects with this implementation.
1. It's not portable (16bits => 32bits or 32bits =>64 bits).
For example:
typedef struct
{
unsigned int A : 3 ;
unsigned int B : 9 ;
unsigned int C : 5 ;
} a_bitf ; // will give different scheme in VC 16 bits & 32 bits !

2. Mix different types in a bitfields structure is problematic.
A little stupid example:
typedef struct
{
WORD a : 1 ;
BYTE b : 1 ;
} my_bitf2 ;

VC6 : sizeof(my_bitf2) = 4.
BC4 & BC5 : sizeof(my_bitf2) = 1.
--------------------------------------------------------------

Further questions:
1. I'm curious to know how the bitfields is implemented in
other C/C++ compilers (watcom c, gnu c, etc.), any idea ?
2. There's no standard, OK, but do you think the VC's implement
is logical and simple to use ?

Cheers.

Erik Funkenbusch

unread,
Nov 2, 1999, 3:00:00 AM11/2/99
to
In actuality, VC's implementation is *MORE* portable than the BC one
if your analysis is correct.

Why? Well, think of it this way. Suppose you have a structure that
you've written to a data file. Then you take that data and want to
read it back using a program compiled with a different compiler (or
even different language, such as VB or Java).

Using the VC method, you can use integral data types to simulate
bitfields using logical operations to extract the data. If BC lays
out the data in a non-intregral type fashion, it becomes more
problematic.

Jean Fan <xiao.ga...@libertysurf.fr> wrote in message

news:381F5AF...@libertysurf.fr...

Chris Uzdavinis

unread,
Nov 2, 1999, 3:00:00 AM11/2/99
to
Bitfields are inherently problematic, as their layout is implementation
dependent, and accessing them is potentially slower than using bools, etc.
While they may save data space, they increase program code size (to
manipulate the bit fields.) One of the truely few "useful" applications for
bitfields is direct hardware access. But other than that, if portability or
minimising "problematic" code is important, an entirely different
representation scheme should be used for data. Bitfields are very low
level, error prone, unportable, potentially slow, and usually are not worth
the hassle.

Chris

Erik Funkenbusch wrote in message <#zJVmoYJ$GA.228@cppssbbsa05>...

Tom

unread,
Nov 4, 1999, 3:00:00 AM11/4/99
to
Jean:
I believe since C++Builder 4, Borland has changed their bitfield
implementation to be compatible with Visual C++. So if you make it
work with VC, it should work with the newer compilers from Borland as
well.
-Tom

0 new messages