(K&R Exercise 2-6)
Write a function setbits(x,p,n,y) that returns x with the n bits that
begin
at position p set to the rightmost n bits of y, leaving the other bits
unchanged.
** p set to the rightmost n bits of y ** This has me at a loss as to
he role
of P. P is passed to the function as one value then reset to the n
most of y
When faced with difficulty, it often helps to start with a concrete
example.
Let me rename the variables a little bit. Having this many single
letter variables is awful for the next person who needs to read it.
setbits( word, index, width, field )
Consider an unsigned 32-bit integer 'word' with the value 0x76543210.
It's binary representation is
0111 0110 0101 0100 0011 0010 0001 0000
Within the 'word', there is a 'field' of 'width' 8 that you want to
set, let's say 0xA1. It's binary representation is
0000 0000 0000 0000 0000 0000 1010 0001
\ /
width=8
For a given 'index' (12) in 'word', set the corresponding bits in
'word' so that the final result is '0x765 A1 210' or
msb lsb
0111 0110 0101 1010 0001 0010 0001 0000
\
index
Think of this as a two part problem. The first problem is to clear
out the bits in 'word' where the 'field' will be inserted. The second
problem is to insert the 'field' into 'word' at the right index.
Hint: For the problem above, try to setup the following.
0111 0110 0101 0000 0000 0010 0001 0000
and
0000 0000 0000 1010 0001 0000 0000 0000
Once you get one concrete example working, test it on other examples
to see if you need to make adjustments to your algorithm.
my code thus far......
unsigned setbits(unsigned x, int p, int n, unsigned y)
{
unsigned mask = ~(~0 << n);
***************************************
* /* p = y & mask; */ *
* /* return x & (mask << (p+1-n)) */ *
* first attempt *
***************************************
return x & (mask << ((((p & 0) | mask) & y)+1-n));
} second attempt and still trying
Im not looking for the answer as I'd really like to work this out for
myself but rather some pointers on where I'm going wrong here or where
my interpretation has gone wrong.
One issue with using '~0' is that the type is restricted to 'int'. If
'int' is 16 bits, and you want to set a field in a 32-bit long, it's
not going to come out right. What I do is define a constant that
defines the mask so that it's easy to change if I need to support bit
operations on larger integer types.
\code snippet
/*!
* \brief Define the integer type used to create a bitmask of all
* ones.
*
* One of the basic constructs used in the \c bits macro library is
* to create a mask that is all ones of a given width starting from
* the least significant bit. This is implemented using the
* expression <tt>~((~0) << width)</tt>. This is used to isolate a
* region of bits to be set or cleared within an integer. This
* concept is needed to implement the set of \c BIT_FIELD macros.
*
* The \c C_BITS_ALL_ONES define can be \c ~0U for \c int sized
* masks, <tt>~UINT32_C(0)</tt> to enable 32-bit support on 16-bit
* integer platforms, or <tt>~UINT64_C(0)</tt> to enable 64-bit
* support. This could be configured using a Makefile or config.h,
* but for now its definition is here.
*
* See \ref C_BITS_ONE for more information.
*/
#define C_BITS_ALL_ONES ( ~UINT32_C(0) )
\endcode
The motivation for 'setbits' is to be able to pack information at the
bit level from several different pieces of data. For example, in
avionics data, the ARINC 429 data standard packs 5 bits of information
into a single 32-bit word.
\comment snippet
/*
* The ARINC 429 standard is a point to point protocol consisting
* of a twisted pair that transmits 32-bit messages from avionics
* devices on an aircraft. The data bus consists of one source with
* many potential receivers. The following is a description of the
* meaning of the message fields.
*
* <ul>
* <li> \c label - This identifies the data type and the
* parameters associated with it for representing
* avionics data. A single avionics device may
* have up to 256 different messages.
* <li> \c sdi - This field is used for multiple receivers to
* identify which receiver is the recipient of
* the avionics data.
* <li> \c data - The avionics data, represented in a number of
* different formats. The common ones are binary
* coded decimal, 2's complement binary, and bit
* fields.
* <li> \c ssm - This field contains hardware equipment
* conditions, operational mode, or validity of
* data content.
* <li> \c parity - The most significant bit is the parity bit,
* typically used to ensure the ARINC 429 message
* has odd parity. Whether this bit is used
* depends on the avionic system design.
* </ul>
*
* Let's look at a real ARINC 429 standard message from an Air Data
* Computer (ADC). The labels are represented in octal form.
*
* Total Air Temperature
* <ul>
* <li> Bit: 1 - 8 Name: Label (211)
* <li> Bit: 9 - 10 Name: SDI
* <li> Bit: 11 - 17 Name: Spare
* <li> Bit: 18 - 29 Name: Total Air Temperature Value \n
* <ul>
* <li> Element Size: 12
* <li> Type: 2's Complement
* <li> Units: Degrees C
* <li> Scale: .25
* <li> State: [-60, 100]
* </ul>
* <li> Bit: 30 - 31 Name: SSM
* <li> Bit: 32 Name: Parity
* </ul>
*/
\endcomment
So, if you wanted to simulate an ARINC 429 data stream, you could take
an array of floating point temperatures in celsius, factor out the
scale factor to convert it to a 2's complement integer representation,
and use 'setbits' to place the 'Total Air Temperature' value's bits at
the right location in the ARINC 429 data word. You can use 'setbits'
to fill in the rest of the fields (Label, SSM, SDI) as needed.
Best regards,
John D.