Sign Extension Implementation in C

781 views Asked by At

Ok I have read a lot about sign extension but I am brand new to C as well as all the 'bitwise operators' so I am still having trouble figuring out how I should actually implement it in C.

I have a function called getField that should return the value of a chunk of bits within a larger bit. It takes three integers: value, hi, and lo plus a bool: isSigned as parameters. For Example this call should return 2:

return getField(9, 5, 2, 0);

My function works except when the number is signed. After reading up on sign extension I think it is my understanding that if isSigned is true then I need to add ones to the bit so in the example above, the solution (0010) would become (111...0010). Here is my the code dealing with making numbers signed (result is equal to what the function would return if isSigned was false):

if (isSigned) {
    return (~result) + 1;
}

This would work if I was supposed to return the 2s complement signed integer but sadly that is not what I am supposed to do. Any assistance is appreciated.

Edit: Here is the entire code for the method...

int getField (int value, int hi, int lo, bool isSigned) {
int mask;

//Make Sure 'hi' is the high value
if (hi < lo) {
    int temp = hi;
    hi = lo;
    lo = temp;
}
int numberOfBits = (hi - lo) + 1;

mask = ((1 << numberOfBits) - 1) << lo;
int result = value & mask;

//Get rid of LSB if value is zero
result = result >> lo;

if (isSigned) { //Sign Extension instead of Twos Complement
    return (~0) << numberOfBits | result;
}
else {
    return result;
}

}

(Note: I did see a post similar to this and I read it, but I was still left very confused so I decided to write a different one. Sorry if this is against the rules.)

2

There are 2 answers

2
nalyd88 On

So I don't really understand what your function is doing but you could get your answer by the following bitwise operations:

int ones = ~0;                  // should give 1111...111111
int shifted_ones = (ones << 4); // should give 1111...110000
result = shifted_ones | result; // should give 1111...110010

// or in one line
result = ((~0) <<4) | result;

I'm not sure if this answers your question. Obviously the number of shifts would need to be a variable.

EDIT

Ok so the first answer while mathematically correct does give a warning (at least with GCC). The compiler detects bits (1s) shifting off the end of the number. Probably not really a production solution but kinda fun. The original solution doesn't have that warning.

int ones = 0b1111; // make the number of ones the same size as the answer.
result = ~ones | result;
1
Soren On

You should probably use the machines own capability of doing sign extension, which you do with a bit of casting of the data types

int getField(unsigned int data, int from, int to, int s)
{
    // assuming 32 bit ints, add error check, ymmw
    data <<= 32-from;
    if (s)
       return ((int)data) >> (32-(from-to));
    return (data >> (32-(from-to)));
}