4
unsigned char *adata = (unsigned char*)malloc(500*sizeof(unsigned char));
unsigned char *single_char = adata+100;

How do I change first four bits in single_char to represent values between 1..10 (int)?

The question came from TCP header structure:

Data Offset: 4 bits 

The number of 32 bit words in the TCP Header.  This indicates where
the data begins.  The TCP header (even one including options) is an
integral number of 32 bits long.

Usually it has value of 4..5, the char value is like 0xA0.

kagali-san
  • 2,964
  • 7
  • 48
  • 87

4 Answers4

6

These have the assumption that you've initialized *single_char to some value. Otherwise the solution caf posted does what you need.

(*single_char) = ((*single_char) & 0xF0) | val;

  1. (*single_char) & 11110000 -- Resets the low 4 bits to 0
  2. | val -- Sets the last 4 bits to value (assuming val is < 16)

If you want to access the last 4 bits you can use unsigned char v = (*single_char) & 0x0F;

If you want to access the higher 4 bits you can just shift the mask up 4 ie.

unsigned char v = (*single_char) & 0xF0;

and to set them:

(*single_char) = ((*single_char) & 0x0F) | (val << 4);

GWW
  • 43,129
  • 11
  • 115
  • 108
  • 1
    In the specific case of the TCP header, the lower 4 bits of this octet are reserved and must be zero. – caf Jan 21 '11 at 06:41
  • 1
    Ah okay, then your solution is better :) – GWW Jan 21 '11 at 07:06
  • @GWW, at the end, it was your solution that worked for me. But it occasionally sets weird values.. (for example, single_char becomes hex 0x86 instead of 0x80). – kagali-san Jan 28 '11 at 19:52
  • 1
    @mhambra: Are you sure the value is initialized to 0 before you tried any bit manipulations? – GWW Jan 28 '11 at 20:42
  • @GWW, doesn't & 0x00001111 just erases the order? – kagali-san Jan 29 '11 at 13:44
  • 1
    @mhambra: Yes but 0b00001111 preserves the low order bits. So in your example, 0x86 = 0b10000110, implying that a few of the lower order bits are set before you do this. – GWW Jan 29 '11 at 17:32
5

This will set the high 4 bits of *single_char to the data offset, and clear the lower 4 bits:

unsigned data_offset = 5; /* Or whatever */

if (data_offset < 0x10)
    *single_char = data_offset << 4;
else
    /* ERROR! */
caf
  • 233,326
  • 40
  • 323
  • 462
  • So it will change the first 4 bits and will not affect lower bits anyway?Thanks! – kagali-san Jan 21 '11 at 09:17
  • @mhambra: "first" is a matter of notation - it will change the *most significant* 4 bits, which is what you want for that field of the TCP header. As I wrote, it will clear (zero) the lower 4 bits - and this is likewise what you want for the TCP header, where those lower 4 bits are reserved and must be zero. – caf Jan 21 '11 at 11:33
2

You can use bitwise operators to access individual bits and modify according to your requirements.

Praveen S
  • 10,355
  • 2
  • 43
  • 69
1

I know this is an old post but I don't want others to read long articles on bitwise operators to get a function similar to these -

//sets b as the first 4 bits of a(this is the one you asked for
void set_h_c(unsigned char *a, unsigned char b)
{
    (*a) = ((*a)&15) | (b<<4);
}

//sets b as the last 4 bits of a(extra)
void set_l_c(unsigned char *a, unsigned char b)
{
    (*a) = ((*a)&240) | b;
}

Hope it helps someone in the future

Thomas
  • 478
  • 4
  • 14