0

For a networking application I need a signed, 2's complement integer. With a custom width. Specified at run time. Assuming the value of the integer falls in the width.

The problem I have is the parity bit. Is there any way of avoid having to manually set the parity bit? Say I have an integer with a width of 11 bits, i'll store it in an array of 2 chars like this:

int myIntWidth = 11;
int32_t myInt= 5;
unsigned char charArray[2] = memcpy(charArray, &myInt, (myIntWidth + 7)/8);
laurisvr
  • 2,724
  • 6
  • 25
  • 44
  • Use bit field to get integer sized as you want. Probably you will want to combine this bit field with simple integer in union (if union is larger then integer) to get simple access to simple modifications. – senfen Apr 29 '15 at 09:16
  • bit fields are inherently non-portable. For a networking application, you need to store the values that the server or device on the other side expects, not what your compiler thinks is right. – gnasher729 Apr 29 '15 at 09:18
  • A problem with using a bit field is that it's size cannot be defined at run time. – laurisvr Apr 29 '15 at 09:33
  • https://graphics.stanford.edu/~seander/bithacks.html#VariableSignExtend – phuclv Apr 29 '15 at 10:40
  • @ Lưu Vĩnh Phúc that is the opposite of what i'm trying to achieve. I'm trying to reduce an int width. – laurisvr Apr 29 '15 at 10:55

2 Answers2

0

It doesn't work like that. It can't work, because you are copying two bytes from the start of myInt but you don't know where the bytes that you are interested in are stored. You also need to know in which order you are supposed to store the bytes. Depending on that, use one of these two codes:

unsigned char charArray [2];
charArray [0] = myInt & 0xff; // Lowest 8 bits
charArray [1] = (myInt >> 8) & 0x07; // Next 3 bits

or

unsigned char charArray [2];
charArray [1] = myInt & 0xff; // Lowest 8 bits
charArray [0] = (myInt >> 8) & 0x07; // Next 3 bits
gnasher729
  • 51,477
  • 5
  • 75
  • 98
  • What do you mean by, "you don't know where the bytes that you want are stored". On little endian the 11 least significant bits will be the first two right? And the problem with 0xff, is that'll only work for 8 bits, i'm desiging it to also work with numbers like 11, and 8 to be determined at runtime. This would require a lookup table then I suppose. – laurisvr Apr 29 '15 at 09:19
  • There's a standard trick to make masks for the low `N` bits: `(1u << N) - 1`. (`N` has to be less than the width of the type you're working in, of course) Alternatively, apply a right shift to the all `1`'s mask, e.g. `0xff >> (8 - N)`. for `0 < N <= 8`. –  Apr 29 '15 at 12:34
0

With the help of a lot of the posts above, I've come up with this solution:

inline void reduceSignedIntWidth(int32_t& destInt, int width)
{
    //create a value mask, with 1's at the masked part
    uint32_t l_mask = (0x01u << width) - 1;

    destInt &= l_mask;
}

It will return the reduced int, with zeros as padding.

laurisvr
  • 2,724
  • 6
  • 25
  • 44
  • What is the point of the for loop? Isn't the result of `l_mask = (l_mask << 1) & 0x01;` always 0? You shift 0x01 for 1 bit to the left which results in 0x02. 0x01 & 0x02 = 0x00. Or did I miss something? :) – rozina Apr 29 '15 at 13:02
  • 1
    Thank you @rozina, it should indeed be `l_mask = (l_mask << 1) | 0x01;` However, I've changed it to way @Hurkyl proposed. Which I think is quite a beautiful trick:) – laurisvr Apr 29 '15 at 13:13