Making sure an enum fits into an unsigned char

A

Alexander Farber

Hi,

I have a UNIX-server written in C, which exchanges messages
with Java clients. In the message the 1 byte is its length,
the 2nd a player number and the 3rd byte is an event id:

/* 0. byte: Total message length in bytes (inlcuding this byte) */
/* 1. byte: Player number (0, 1 or 2) */
/* 2. byte: Event id (10 - 22) */
/* 3.-255.: Argument (252 bytes or 126 big-endian UTF-16 chars) */

typedef unsigned char byte;

typedef struct {
byte len,
num,
id,
arg[MAXARG];
} msg;

For the event ids I currently use #defines:

#define PREF_NAME 10
#define PREF_PASS 11
#define PREF_CHAT 12
#define PREF_CARD 13

But I would actually prefer to use enums instead, something like:

enum event_id {
PREF_NAME = 10,
PREF_PASS,
PREF_CHAT,
PREF_CARD
}

However enums are integers, aren't they? Could
I somehow specify that my enums are 8 bit long only?

One more question: how do you use typedef's with enum's?
I've tried to change this code:

enum direction {
FROM,
TO
};

void print_node(unsigned i, unsigned j, enum direction dir, const node
*np);

To the following, but get strange unrelated error messages
(I suspect that I declare a variable "direction" there instead):

typedef enum {
FROM,
TO
} direction;

void print_node(unsigned i, unsigned j, direction dir, const node *np);

Thank you
Alex

PS: I'm using gcc 3.3.5 on OpenBSD 3.7.
 
S

SM Ryan

# enum event_id {
# PREF_NAME = 10,
# PREF_PASS,
# PREF_CHAT,
# PREF_CARD
# }
#
# However enums are integers, aren't they? Could
# I somehow specify that my enums are 8 bit long only?

Use byte instead of enum event_id.

byte variable = PREF_NAME;

This is allowed and assuming PREF_NAME is in the range of values
byte can hold, there will be no loss of value.


# One more question: how do you use typedef's with enum's?
# I've tried to change this code:
#
# enum direction {
# FROM,
# TO
# };
#
# void print_node(unsigned i, unsigned j, enum direction dir, const node
# *np);
#
# To the following, but get strange unrelated error messages
# (I suspect that I declare a variable "direction" there instead):
#
# typedef enum {
# FROM,
# TO
# } direction;

If you want to better control over the allocation of direction
objects, you can use
typedef byte direction;
instead.

Without seeing the error message, it's hard to guess. Does the typedef
proceed any reference to the type name.
 
S

Suman

Alexander said:
Hi,

I have a UNIX-server written in C, which exchanges messages
with Java clients. In the message the 1 byte is its length,
the 2nd a player number and the 3rd byte is an event id:

/* 0. byte: Total message length in bytes (inlcuding this byte) */
/* 1. byte: Player number (0, 1 or 2) */
/* 2. byte: Event id (10 - 22) */
/* 3.-255.: Argument (252 bytes or 126 big-endian UTF-16 chars) */

typedef unsigned char byte;

typedef struct {
byte len,
num,
id,
arg[MAXARG];
} msg;

For the event ids I currently use #defines:

#define PREF_NAME 10
#define PREF_PASS 11
#define PREF_CHAT 12
#define PREF_CARD 13

But I would actually prefer to use enums instead, something like:

enum event_id {
PREF_NAME = 10,
PREF_PASS,
PREF_CHAT,
PREF_CARD
}

However enums are integers, aren't they?

Quotes from the C99 draft that might help you:

Enum:
Constraints:
....
"The identifiers in an enumerator list are
declared as constants that have type int and
may appear wherever such are permitted..."

and a footnote:
"An implementation may delay the choice of which
integer type until all enumeration constants have
been seen."
Could
I somehow specify that my enums are 8 bit long only?

Why would you want that?
One more question: how do you use typedef's with enum's?
I've tried to change this code:

enum direction {

typedef enum direction {
FROM,
TO
};

} direction;
should work.
void print_node(unsigned i, unsigned j, enum direction dir, const node
*np);

To the following, but get strange unrelated error messages
(I suspect that I declare a variable "direction" there instead):

Possible, use your text editor's search option to the hilt ;-)
But enums have their own namespace, and even the following:

typedef enum _myBool { FALSEY, TRUEY } _myBool;
void demo( _myBool f )
{
int _myBool;
/* following are to get rid of unused variable warning */
f = !f;
_myBool = 1;
}

int main()
{
}

compiles (with gcc -std=c99 -W -Wall -pedantic) without any warnings.
Had you posted the error message(s), it would have been handy.
typedef enum {
FROM,
TO
} direction;

Should work as well!
void print_node(unsigned i, unsigned j, direction dir, const node *np);

Thank you
Alex

PS: I'm using gcc 3.3.5 on OpenBSD 3.7.
HTH
 
A

Anton Petrusevich

Alexander said:
I have a UNIX-server written in C, which exchanges messages
with Java clients. In the message the 1 byte is its length,
the 2nd a player number and the 3rd byte is an event id:
/* 0. byte: Total message length in bytes (inlcuding this byte) */
/* 1. byte: Player number (0, 1 or 2) */
/* 2. byte: Event id (10 - 22) */
/* 3.-255.: Argument (252 bytes or 126 big-endian UTF-16 chars) */
typedef unsigned char byte;
typedef struct {
byte len,
num,
id,
arg[MAXARG];
} msg;

How do you know that there's no padding between fields? I would suggest to
think about it.
 
A

Alexander Farber

Hi,
How do you know that there's no padding between fields?
I would suggest to think about it.

I dunno, it seems to work ok on Linux and OpenBSD:

/* 0. byte: Total message length in bytes (inlcuding this byte) */
/* 1. byte: Player number (0, 1 or 2) */
/* 2. byte: Event id (10 - 22) */
/* 3.-255.: Argument (252 bytes or 126 big-endian UTF-16 chars) */

typedef unsigned char byte;

typedef struct {
byte len,
num,
id,
arg[MAXARG];
} msg;

/* an element of a singly-linked list or queue */
typedef struct node_s {
struct node_s *next;
#ifndef NDEBUG
/* used to track (de)allocated nodes */
unsigned memid;
#endif
union {
msg m;
byte buf[MAXBUF];
} node_u;
#define node_len node_u.m.len
#define node_num node_u.m.num
#define node_id node_u.m.id
#define node_arg node_u.m.arg
#define node_buf node_u.buf
} node;

And then I read() and writev() those messages (after a poll()):

/* on the 1st time try to read 3 bytes (i.e. no more */
/* than the min. message length) to find out the length */

if (0 == cp->nfrom)
n = read(cp->fd, np->node_buf, 3);
else
n = read(cp->fd, &(np->node_buf[cp->nfrom]),
np->node_len - cp->nfrom);
.........

iov[0].iov_base = np->node_buf + cp->nto;
iov[0].iov_len = np->node_len - cp->nto;

for (k = 1, np = np->next; np && k < IOV_MAX; k++, np = np->next) {
iov[k].iov_base = np->node_buf;
iov[k].iov_len = np->node_len;
}
n = writev(cp->fd, iov, k);
........

I.e. I refer to the node_u.buf member in my read()/writev() calls.

Do you have a better suggestion please?

Regards
Alex
 
A

Alexander Farber

Hi Suman,
Why would you want that?

I need that because my messages should be at most 255 bytes long, with
the 1st byte containing the message length.

That way I can poll(), then read the 1st byte (ok the first 3 bytes)
without blocking and then poll() again and read the rest.

I have a non-forking iterative server and must be sure that no client
I/O will block or my server will hang for everyone

Regards
Alex
 
R

Richard Bos

SM Ryan said:
# enum event_id {
# PREF_NAME = 10,
# PREF_PASS,
# PREF_CHAT,
# PREF_CARD
# }
#
# However enums are integers, aren't they? Could
# I somehow specify that my enums are 8 bit long only?

Use byte instead of enum event_id.

byte variable = PREF_NAME;

There is no such thing in C.

Richard
 
A

Anton Petrusevich

Alexander said:
I dunno, it seems to work ok on Linux and OpenBSD:

I would say: it accidentally works. You are really streaming dumps of
memory. I would think about host<->network translation routines without any
padding assumptions of structure members.
 
S

Suman

Alexander said:
Hi Suman,



I need that because my messages should be at most 255 bytes long, with
the 1st byte containing the message length.

That way I can poll(), then read the 1st byte (ok the first 3 bytes)
without blocking and then poll() again and read the rest.

Actually, I should have formulated my query differently. Should have
been:
Is it that you want your enums to be exactly 8 bits?
If it is yes, I think you need to use bit-fields, not enums.
Manipulating them might be a pain, but that's the way it is.

OTOH, if it is not, the quoted footnote in my earlier post
should be of some help.

And finally, I am sure you know this, but still, a byte
as typedef-ed by you has CHAR_BIT number of bits,
and that the value of CHAR_BIT is often but not necessarily 8.
 
S

SM Ryan

(e-mail address removed) (Richard Bos) wrote:
#
# > # enum event_id {
# > # PREF_NAME = 10,
# > # PREF_PASS,
# > # PREF_CHAT,
# > # PREF_CARD
# > # }
# > #
# > # However enums are integers, aren't they? Could
# > # I somehow specify that my enums are 8 bit long only?
# >
# > Use byte instead of enum event_id.
# >
# > byte variable = PREF_NAME;
#
# There is no such thing in C.

The original poster included a typedef for byte. Some of us don't
need to quote an entire post to remember what was there.

Insert apology in space provided.
[___________________________________________________]
[___________________________________________________]
[___________________________________________________]
[___________________________________________________]
 
F

Flash Gordon

SM said:
(e-mail address removed) (Richard Bos) wrote:
# SM Ryan <[email protected]> wrote:

# > byte variable = PREF_NAME;
#
# There is no such thing in C.

The original poster included a typedef for byte. Some of us don't
need to quote an entire post to remember what was there.

Insert apology in space provided.

However, as you well know (or should do by now), other people might not
have received that message and you can't remember something you haven't
seen.
 
S

SM Ryan

# SM Ryan wrote:
# > (e-mail address removed) (Richard Bos) wrote:
#
# <snip>
#
# > # > byte variable = PREF_NAME;
# > #
# > # There is no such thing in C.
# >
# > The original poster included a typedef for byte. Some of us don't
# > need to quote an entire post to remember what was there.
# >
# > Insert apology in space provided.
#
# However, as you well know (or should do by now), other people might not
# have received that message and you can't remember something you haven't
# seen.

When in a hole, stop digging
 
F

Flash Gordon

SM said:
# SM Ryan wrote:
# > (e-mail address removed) (Richard Bos) wrote:
#
# <snip>
#
# > # > byte variable = PREF_NAME;
# > #
# > # There is no such thing in C.
# >
# > The original poster included a typedef for byte. Some of us don't
# > need to quote an entire post to remember what was there.
# >
# > Insert apology in space provided.
#
# However, as you well know (or should do by now), other people might not
# have received that message and you can't remember something you haven't
# seen.

When in a hole, stop digging

If I ever find myself in a hole I'll remember that. However, I'm not in
one and don't thing Richard Bos is either. I stand by what I said and
see nothing wrong with Richard's comment based on the context provided.
 
C

CBFalconer

Alexander said:
I have a UNIX-server written in C, which exchanges messages
with Java clients. In the message the 1 byte is its length,
the 2nd a player number and the 3rd byte is an event id:

/* 0. byte: Total message length in bytes (inlcuding this byte) */
/* 1. byte: Player number (0, 1 or 2) */
/* 2. byte: Event id (10 - 22) */
/* 3.-255.: Argument (252 bytes or 126 big-endian UTF-16 chars) */

typedef unsigned char byte;

typedef struct {
byte len,
num,
id,
arg[MAXARG];
} msg;

For the event ids I currently use #defines:

#define PREF_NAME 10
#define PREF_PASS 11
#define PREF_CHAT 12
#define PREF_CARD 13

But I would actually prefer to use enums instead, something like:

enum event_id {
PREF_NAME = 10,
PREF_PASS,
PREF_CHAT,
PREF_CARD
}

However enums are integers, aren't they? Could
I somehow specify that my enums are 8 bit long only?

You should have no difficulty as long as the enum values are within
the range of an unsigned char. Just substitude the enum definition
for the #defines. I have also used them for bit mapped errors by
something like:

typedef enum errcode = {NO_ERR,
ERR_1b,
ERR_2b,
ERR_4b = 4,
ERR_8b = 8} errcode;
 
R

Richard Bos

SM Ryan said:
(e-mail address removed) (Richard Bos) wrote:
#
# > # enum event_id {
# > # PREF_NAME = 10,
# > # PREF_PASS,
# > # PREF_CHAT,
# > # PREF_CARD
# > # }
# > #
# > # However enums are integers, aren't they? Could
# > # I somehow specify that my enums are 8 bit long only?
# >
# > Use byte instead of enum event_id.
# >
# > byte variable = PREF_NAME;
#
# There is no such thing in C.

The original poster included a typedef for byte.

Then you should've quoted that.
Some of us don't need to quote an entire post to remember what was there.

Some of us understand better than that how Usenet works.

Richard
 
S

SM Ryan

(e-mail address removed) (Richard Bos) wrote:

# Some of us understand better than that how Usenet works.

Then try this

telnet post.news.xs4all.nl 119
article <[email protected]>
quit
 
C

CBFalconer

Richard said:
Then you should've quoted that.


Some of us understand better than that how Usenet works.

In fact some of us are even capable of using normal quote markers.
 
K

Keith Thompson

SM Ryan said:
(e-mail address removed) (Richard Bos) wrote:

# Some of us understand better than that how Usenet works.

Then try this

telnet post.news.xs4all.nl 119
article <[email protected]>
quit

% telnet post.news.xs4all.nl 119
Trying 194.109.133.8...

It hangs indefinitely. I don't think post.news.xs4all.nl wants to
talk to me.

And I'll take this opportunity to ask, one more time, why you insist
on using your non-traditional '#' quote character. You know it causes
problems for some readers. You know that it would be trivial for you
to use '>', as almost everyone else does, and that doing so would
immediately cause you to be taken more seriously. And I know that I'm
wasting my time asking this again.
 
S

SM Ryan

YACLCNKWB.

Yet another comp.lang.c netkop wannabe.


# > (e-mail address removed) (Richard Bos) wrote:
# >
# > # Some of us understand better than that how Usenet works.
# >
# > Then try this
# >
# > telnet post.news.xs4all.nl 119
# > article <[email protected]>
# > quit
#
# % telnet post.news.xs4all.nl 119
# Trying 194.109.133.8...
#
# It hangs indefinitely. I don't think post.news.xs4all.nl wants to
# talk to me.
#
# And I'll take this opportunity to ask, one more time, why you insist
# on using your non-traditional '#' quote character. You know it causes
# problems for some readers. You know that it would be trivial for you
# to use '>', as almost everyone else does, and that doing so would
# immediately cause you to be taken more seriously. And I know that I'm
# wasting my time asking this again.
#
# --
# Keith Thompson (The_Other_Keith) (e-mail address removed) <http://www.ghoti.net/~kst>
# San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
# We must do something. This is something. Therefore, we must do this.
#
#
 

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,763
Messages
2,569,562
Members
45,038
Latest member
OrderProperKetocapsules

Latest Threads

Top