Topic: enum - several usage restrictions


Author: ao@infinet.com (Mike Harrold)
Date: 1996/09/08
Raw View
Alexandre Oliva (oliva@dcc.unicamp.br) wrote:
: >>>>> In    article   <01bb9bdc$9f047340$511b41c2@viking.marktest.pt>,
: >>>>> "Antonio Fatela" <afatela@marktest.pt> writes:

: Antonio>  My suggestion was to  allow to assign  a  integral type to a
: Antonio> enum. So it will became some how like:

: Antonio> enum type_e::char
: Antonio> {
: Antonio> =09BOLD, NORMAL=09
: Antonio> };
: Antonio> type_e type;

: If type_e  is used to  declare a class member, as  it is in the code I
: snipped out, you may declare it as a bitfield:

: struct foo {
:   type_e bar:8;
: };

: This is valid as  of the current DWP.   Anyway, memory  allocation for
: bitfields is implementation dependent...

Are there not also performance issues to consider with bitfields?

There is another way to accomplish this (albeit somewhat messy), something
I have done to great affect. It is not 100% guaranteed with a struct, but
can be done with a class:

  class foo {

  public:
    enum type_e {
 BOLD = 0,
 NORMAL = 1
    };

  private:
    ubit8  __bar;

  public:

    foo(type_e b)            { bar = b; }

    type_e bar() const       { return (type_e) bar; }
    void   set_bar(type_e b) { __bar = (ubit8) b; }
  };

The cast from the ubit8 (typedef'd as an unsigned char--sorry, I use these
all the time ;) ) to a type_e is, ehrm, "risky" under usual circumstances,
but remember that since __bar can only be accessed by the class itself, you
can control this casting at the class level, and not have to worry about what
happens elsewhere in the program. If type_e gets larger than what can be held
by the ubit8, you can make the change within the class and not worry about
changes in the rest of the program.

/Mike

--
+--------------------------------------------------------------------------+
| Take the cheese to sickbay, the Doctor should take a look at it as soon  |
| as possible.  --  B'lanna Torres - Star Trek Voyager - 'Learning Curve'. |
+--------------------------------------------------------------------------+


[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1996/09/09
Raw View
"Antonio Fatela" <afatela@marktest.pt> writes:

> Suppose you have the following structure:
> struct line_t
> {
>  enum type_e
>  {
>   BOLD, NORMAL
>  };
>  type_e type;
>  POINT p1, p2;
> };
>
> There will be millions of objects of this kind allocated at the same time.
> In this situation, memory used is critical. As type_e will be integral, in
> 32 bit machines, it will take 2*sizeof(POINT)+4 bytes to store line_t. In
> some situation this is inadmissible.

First, the guarantee is that the underlying type will be an integral
type.  Whether it is a char, a short or an int (in any of their signed
or unsigned variants) is implementation defined.

Second, you don't indicate the type of POINT.  On most 32 bit systems,
if it contains an int (or anything larger), the compiler will align it
on a multiple of 4 bytes.  So that even with your solution (declaring
the actual value as char), it will probably make the struct 4 bytes
bigger.

If space is at a premium, use the solution proposed by Steve Clamage:
declare it as a bit field.  Note, however, that unless p1 and p2 are
also declared as bit fields (which can only be done if POINT is an
integral type), then declaring type as a bit field probably won't buy
you much.  (Also, of course, if point is a bit field, then you cannot
take its address.)

Although it breaks encapsulation somewhat, if space was really at a
premium, I'd define two types: Line and PackedLine, with conversion
operators between them.  My arrays would contain PackedLine's, but I'd
work locally on Line's.  The PackedLine would break the encapsulation of
POINT, in order to pack it as well.  While this is not the sort of thing
I'd recommend unless it is really necessary, I can see cases where it is
justified.  (In this case, your names suggest typesetting; if POINT
specifies a position on the page, it's highly unlikely that future
developments will cause it to be anything other than two integers.  If,
by chance, it changed to two doubles, it cannot be packed anyway, and
changing the definition of PackedLine to a typedef to Line would not
require any other changes in the code.)

--
James Kanze           (+33) 88 14 49 00          email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle --
                            -- Beratung in industrieller Datenverarbeitung
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: seurer@rchland.ibm.com (Bill Seurer)
Date: 1996/09/09
Raw View
In article <50t9ro$lhr@news1.infinet.com>, ao@infinet.com (Mike Harrold) writes:
|> Are there not also performance issues to consider with bitfields?

That is entirely implementation dependent.  For some code that I
have been trying to both make use less heap memory and run faster (yeah,
sometimes I feel like a masochist) I noticed no performance degradation in
using bitfields (xlC compiler on AIX 4.1).
--

- Bill Seurer     ID Tools and Compiler Development      IBM Rochester, MN
  Business: BillSeurer@vnet.ibm.com               Home: BillSeurer@aol.com
  WWW:  http://members.aol.com/BillSeurer


[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Antonio Fatela" <afatela@marktest.pt>
Date: 1996/09/11
Raw View
In all of the comments about enum storage specification, the main topics
are:
 1) char, short, int, long storage is implementation dependent, so why
define storage of enum as one of them, (BW: why do we need more than one
type of integers :-) )?
 2) It can be solved with bitfields.
 3) We can store it on char, short, int, long and then have some conversion
methods for read and write enum - several ways, some of them more
complicated than others.
 4) In most 32 bit implementations the compiler will align it
on a multiple of 4 bytes
 5) My favorite (at least till now): 'forget' enums, use them just for
define constants, a good replacement for '#define' directive.

Of course, integer types storage is implementation dependent, but we can
always, either by 'typedef', or by '#define' define some fixed storage type
like 'byte', 'int16' etc, in an include file dependent from the
implementation. It is much more difficult to control and use bitfields, and
their implementation varies to much.
If all the time we need to declare a enum variable we need to define at
least 2 methods (read and write cast), the developing time and code
complexity would have an enormous increase.
With respect with alignment, most used compilers (I think) have some
options to disable it. Of course this arise some other issues about
performance.

About their strong the type restrictions, I think the compiler should
generate a warning (NOT ERROR!) in case of possibly incorrect operations
(e.g. assigning a enum variable an integer):

I think, that the real point in discussion is if enum types are really
important for the C++ language (of course they can not be deleted because
of C compatibility). If they are, we should allow storage definition and
have weaker type checking:

If not, well, let them rest in peace, waiting for better days!

___________________________________________________________________
Antonio M Fatela                 E-mail: afatela@marktest.pt
MARKTEST                         Fax:    +351 +1 3535338
DT1 - Dpto. de Informatica       Phone:  3535371 - 3535418/21/36
Alameda Santo Antonio dos Capuchos, N. 4 - 4
1100 Lisboa
PORTUGAL
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: "Antonio Fatela" <afatela@marktest.pt>
Date: 1996/09/06
Raw View
Suppose you have the following structure:
struct line_t
{
 enum type_e
 {
  BOLD, NORMAL
 };
 type_e type;
 POINT p1, p2;
};

There will be millions of objects of this kind allocated at the same time.
In this situation, memory used is critical. As type_e will be integral, in
32 bit machines, it will take 2*sizeof(POINT)+4 bytes to store line_t. In
some situation this is inadmissible.
If this structure is to be saved in binary files, the only way to move an
aplication from 16 bits into 32 bits is to change 'type_e type' to 'int16
type'.
My implementation would be:

struct line_t
{
 enum type_e
 {
  BOLD, NORMAL
 };
 /*type_e*/char type;
 POINT p1, p2;
};
Of course this is a weaker implementation:
 1) You don't perform the proper type check in 'type'.
 2) The debugger can not tell that 0 means BOLD and 1 NORMAL.
 3) It becomes harder to maintain code (if poor commented)
 4) It is almost the same as defining BOLD as 0 and NORMAL as 1 (of course
as lots of differences)

My suggestion was to allow to assign a integral type to a enum. So it will
became some how like:

enum type_e
{
 BOLD, NORMAL
};
type_e::char type;

or

enum type_e::char
{
 BOLD, NORMAL
};
type_e type;

I disagree also from the impossibility of performing some integral
operations directly with enum types (without cast) - this will lead to more
define dependence.

It would be nice it the final version of standard could solve this
problems.



___________________________________________________________________
Antonio M Fatela                 E-mail: afatela@marktest.pt
MARKTEST                         Fax:    +351 +1 3535338
DT1 - Dpto. de Informatica       Phone:  3535371 - 3535418/21/36
Alameda Santo Antonio dos Capuchos, N. 4 - 4
1100 Lisboa
PORTUGAL


[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: clamage@taumet.Eng.Sun.COM (Steve Clamage)
Date: 1996/09/06
Raw View
In article 511b41c2@viking.marktest.pt, "Antonio Fatela" <afatela@marktest.pt> writes:
>Suppose you have the following structure:
>struct line_t
>{
> enum type_e
> {
>  BOLD, NORMAL
> };
> type_e type;
> POINT p1, p2;
>};
>
>There will be millions of objects of this kind allocated at the same time.
>In this situation, memory used is critical. As type_e will be integral, in
>32 bit machines, it will take 2*sizeof(POINT)+4 bytes to store line_t. In
>some situation this is inadmissible.

You can use bitfields to address that particular problem:

 struct line_t {
  type_e type : 1;
  ...
 };
One bit is enough for type_e, and will ensure the struct takes
no more space than required by the architecture. You probably
want to put the bitfield last to reduce alignment requirements,
and you probably want to specify more than one bit in case you
add more enumerators later.

This approach doesn't work for arrays, however, unless you make an
array of a struct something like this:

 struct type_e_struct {
  type_e t : 1; // or 8 or whatever
  type_e_struct(type_e e) : t(e) { } // convert type_e to struct
  operator type_e() { return t; }    // convert struct to type_e
 };


Your suggestions about weakening the type restrictions on enums
probably would not be accepted. Enums in C++ were deliberately
made stronger than in C.

---
Steve Clamage, stephen.clamage@eng.sun.com
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Alexandre Oliva <oliva@dcc.unicamp.br>
Date: 1996/09/06
Raw View
>>>>> In    article   <01bb9bdc$9f047340$511b41c2@viking.marktest.pt>,
>>>>> "Antonio Fatela" <afatela@marktest.pt> writes:

Antonio>  My suggestion was to  allow to assign  a  integral type to a
Antonio> enum. So it will became some how like:

Antonio> enum type_e::char
Antonio> {
Antonio> =09BOLD, NORMAL=09
Antonio> };
Antonio> type_e type;

If type_e  is used to  declare a class member, as  it is in the code I
snipped out, you may declare it as a bitfield:

struct foo {
  type_e bar:8;
};

This is valid as  of the current DWP.   Anyway, memory  allocation for
bitfields is implementation dependent...

--
Alexandre Oliva
oliva@dcc.unicamp.br
Universidade Estadual de Campinas, S=E3o Paulo, Brasil
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]