What is the correct way to create a data type with discrete values

In a struct I have an 8 bit value called bmRequestType. There are three fields in the 8 bits like this:

bmRequestType 8 bits D7..D0 Bit-Map

D7 Data Phase Transfer Direction
0 = Host to Device
1 = Device to Host

D6..5 Type
0 = Standard
1 = Class
2 = Vendor
3 = Reserved

D4..0 Recipient
0 = Device
1 = Interface
2 = Endpoint
3 = Other
Values 4..31 = Reserved

I am wondering what is the best way to express this in C and C++.

I can declare this as an 8 bit unsigned integer and just use numbers to assign value to it but that is not a good idea

OR

I can have #define constant for each of the fields which can be logically ORed togther like this e.g

#define device_to_host 0x80
#define vendor 0x40
#define endpoint 0x02
uint8 bmRequestType = device_to_host | vendor | endpoint

OR

Another way is to create a struct with bit fields:

typedef struct bmRequestType_t {
uint8 direction: 1;
uint8 type: 2;
uint8 recipient: 5
} bmRequestType;

OR

I could create enum for each bit field and declare as enum, I have not filled in the code for the enums as this only demonstrates the concept

enum direction_t{
...
}

enum type_t{
...
}

enum recipient_t{
...
}


typedef struct bmRequestType_t {
direction_t direction: 1;
type_t type: 2;
recipient_t recipient: 5
} bmRequestType;


Which of these is the most appropriate way? I mean best practice?

Please that that I am trying to understand this from perspective of C and also C++.
Last edited on
Bit fields are perfect for this kind of hardware interface. If it were software only, a full byte for each thing isn't so wasteful on today's computers, and you might do it that way. But on an embedded device or if sending the byte as a command to hardware, use the bitfield.

You can also use vector<bool> which is specialized to use 1 bit per Boolean for most modern compilers, esp if you use multiples of 8 when you allocate it:

http://www.cplusplus.com/reference/vector/vector-bool/

so I guess more explicitly..
if its C, use struct/bitfield.
if its c++, use vector<bool> and check that it is using 1 bit per. if not, use C approach.

if its in software, it really depends, but its generally easier to code and faster to just waste a byte for each bit and keep it simple.


Last edited on
Thanks, that simplifies things. I am wondering about this other thing:

/* PID field values/state */

#define TD_DATA_PID 0 /* control pipe state for td_sie_done */
#define TD_STATUS_PID 2 /* control pipe state for td_sie_done */
#define TD_DONE_PID 4 /* control pipe state for td_sie_done */
#define TD_DELETE_PID 0xee /* pipe command for td_sie_done */
#define TD_SETUP_PID 0xd /* also used for control pipe state for tf_sie_done */
#define TD_IN_PID 0x9
#define TD_OUT_PID 0x1
#define TD_SOF_PID 0x5
#define TD_PREAMBLE_PID 0xc
#define TD_NAK_PID 0xa
#define TD_STALL_PID 0xe
#define TD_DATA0_PID 0x3
#define TD_DATA1_PID 0xb

#define TD_NORMAL_TIMEOUT 0
#define TD_LONG_TIMEOUT 1

enum TD_CTRL_BITS
{
TD_CTRL_ARM = 0x01,
TD_CTRL_ISOCH = 0x10,
TD_CTRL_SYNC_SOF = 0x20,
TD_CTRL_DTOGGLE = 0x40,
TD_CTRL_PREAMBLE = 0x80
};


enum TD_STATUS_BITS
{
TD_STATUS_ACK = 0x01,
TD_STATUS_ERROR = 0x02,
TD_STATUS_TIMEOUT = 0x04,
TD_STATUS_SEQ = 0x08,
TD_STATUS_SETUP = 0x10,
TD_STATUS_OVERFLOW = 0x20,
TD_STATUS_NAK = 0x40,
TD_STATUS_STALL = 0x80
};

Now please take note. All of the code above is actually declaring constants. However, there is a subtle difference. All the #define values are used standalone, they are not not logically ORed together to create a single constant. However, the constants created via enum actually name the different bits in a single byte and in this may maybe they can be used as bit mask or they can be logically ORed together. I don't know if C/C++ is supposed to allow logical operation on fields of an enaum, is it to?

I am wondering why the enum were also not just created using #define. What do you think?
enums are a type.

you can say

TD_CTRL_BITS myctrl = TD_CTRL_ARM;

for example. Its nothing like #define constants.
Topic archived. No new replies allowed.