Sign Extending an int in C

后端 未结 2 1766
萌比男神i
萌比男神i 2021-01-23 10:50

So I am having some trouble getting a field of an int and then sign extending it. I have a method that gets the field of an int.

getField(int value, int hi, int         


        
相关标签:
2条回答
  • 2021-01-23 11:09

    There's an awful lot of reading between the lines going on here. However, if getField(7, 1, 0) returns 3 and you need getFieldSignExtended(15, 2, 0) to return -3 and getFieldSignExtended(3, 2, 0) to return +3, then this might be what you're after.

    The concept is that you treat an n-bit field from bits hi:lo of the original value as a 2's complement number. If the first bit of the n bits is a 1, then you want the n-bit field treated as a negative number. If the first bit of the 3-bit field is a 0, then you want it treated as a positive number.

    #include <assert.h>
    #include <limits.h>
    #include <stdio.h>
    
    extern int getFieldSignExtended(int value, int hi, int lo);
    
    enum { INT_BITS = CHAR_BIT * sizeof(int) };
    
    int getFieldSignExtended(int value, int hi, int lo)
    {
        assert(lo >= 0);
        assert(hi > lo);
        assert(hi < INT_BITS - 1);
        int bits = (value >> lo) & ((1 << (hi - lo + 1)) - 1);
        if (bits & (1 << (hi - lo)))
            return(bits | (~0U << (hi - lo)));
        else
            return(bits);
    }
    

    The 3 assertions are straight-forward; the only controversial one is that the code refuses to deal with bit 31. If you invoked it with hi = 31 and lo = 0, then the shift (hi - lo + 1) is too big and the behaviour is undefined. You also run into the implementation-defined behaviour of right shifting a negative number. It would be possible to fix these issues by taking an unsigned integer argument and not doing the & operation if hi - lo + 1 == INT_BITS. Fixing the issues is left as an exercise for the reader.

    The assignment to bits shifts the value right, and masks it with the correct number of bits. The (1 << (hi - lo + 1)) - 1 shifts 1 left by one more than than the number of bits in the field, then subtracts one to generate a string of binary 1's for each bit position in the field. For example, for hi = 2, lo = 0, this shifts 1 left 3 places, yields binary 1000; subtracting 1 gives 0111, so the correct 3 bits are selected. So, bits contains the appropriate set of bits for the n-bit integer.

    The if test checks whether the most significant bit of the n-bit integer is set. If the sign bit isn't set, we simply return the value bits. If the sign bit is set, then we have a tricky calculation to perform — one that was (very) wrong in the first draft of this answer. Suppose we have a field of 3 bits = 101. As a 3-bit 2's complement number, that represents -3. We need to extend that to the left with all 1's to generate the full-size -1. The value of ~0 is all bits 1; when that's shifted left by hi - lo bits, it leaves a series of zeros for the non-sign-bits of the value. It would also work if you shifted left by hi - lo + 1, but there's extra computation needed for the + 1 that isn't necessary.

    I used this test harness to satisfy myself that the code was working correctly. The systematic test output is rigorous (on smallish numbers). It ensures that the calculated value matches the expected value. The 'exhaustive' test isn't really exhaustive; it only tests one value, and it is more for observing problems (such as that using hi = 31 and lo = 0 gives an erroneous answer of 0 on my machine) and patterns.

    static const struct
    {
        int  value;
        int  hi;
        int  lo;
        int  wanted;
    } tests[] =
    {
        {   0x0F,  1,  0,   -1 },
        {   0x0F,  2,  0,   -1 },
        {   0x0F,  2,  1,   -1 },
        {   0x0F,  3,  1,   -1 },
        {   0x0F,  4,  2,   +3 },
        {   0x0F,  5,  0,  +15 },
        {   0x0F,  5,  1,   +7 },
        {   0x0F,  5,  2,   +3 },
        {   0x0F,  5,  3,   +1 },
        {   0x0F,  5,  4,    0 },
        {   0x03,  2,  0,   +3 },
        {   0xF3,  2,  0,   +3 },
        {   0xF3,  3,  0,   +3 },
        {   0xF3,  4,  0,  -13 },
        {   0xF3,  5,  0,  -13 },
        {   0xF3,  6,  0,  -13 },
        {   0xF3,  7,  0,  -13 },
        {   0xF3,  7,  1,   -7 },
        {   0xF3,  7,  2,   -4 },
        {   0xF3,  7,  3,   -2 },
        {   0xF3,  7,  4,   -1 },
        {   0xF3,  8,  0, 0xF3 },
    };
    enum { NUM_TESTS = sizeof(tests) / sizeof(tests[0]) };
    static const char s_pass[] = "== PASS ==";
    static const char s_fail[] = "!! FAIL !!";
    
    static void systematic_test(void)
    {
        int fail = 0;
        for (int i = 0; i < NUM_TESTS; i++)
        {
            char const *pf = s_fail;
            int actual = getFieldSignExtended(tests[i].value, tests[i].hi, tests[i].lo);
            if (actual == tests[i].wanted)
                pf = s_pass;
            else
                fail++;
            printf("%s GFSX(%+4d = 0x%.4X, %d, %d) = %+4d = 0x%.8X (wanted %+4d = 0x%.8X)\n",
                   pf, tests[i].value, tests[i].value, tests[i].hi, tests[i].lo, actual, actual,
                   tests[i].wanted, tests[i].wanted);
        }
        printf("%s\n", (fail == 0) ? s_pass : s_fail);
    }
    
    static void exhaustive_test(void)
    {
        int value = 0x5FA03CE7;
        for (int i = 1; i < INT_BITS - 1; i++)
        {
            for (int j = 0; j < i; j++)
            {
                int actual = getFieldSignExtended(value, i, j);
                printf("%11sGFSX(%d = 0x%X, %2d, %2d) = %+10d = 0x%.8X\n", "",
                        value, value, i, j, actual, actual);
            }
        }
    }
    
    int main(void)
    {
        int result1 = getFieldSignExtended(15, 2, 0);
        int result2 = getFieldSignExtended( 3, 2, 0);
        printf("GFSX(15, 2, 0) = %+d = 0x%.8X\n", result1, result1);
        printf("GFSX( 3, 2, 0) = %+d = 0x%.8X\n", result2, result2);
    
        printf("\nSystematic test\n");
        systematic_test();
    
        printf("\nExhaustive test\n");
        exhaustive_test();
    
        return(0);
    }
    

    This is the output of the test code before the exhaustive test, plus a small selection of the output from the exhaustive test:

    GFSX(15, 2, 0) = -1 = 0xFFFFFFFF
    GFSX( 3, 2, 0) = +3 = 0x00000003
    
    Systematic test
    == PASS == GFSX( +15 = 0x000F, 1, 0) =   -1 = 0xFFFFFFFF (wanted   -1 = 0xFFFFFFFF)
    == PASS == GFSX( +15 = 0x000F, 2, 0) =   -1 = 0xFFFFFFFF (wanted   -1 = 0xFFFFFFFF)
    == PASS == GFSX( +15 = 0x000F, 2, 1) =   -1 = 0xFFFFFFFF (wanted   -1 = 0xFFFFFFFF)
    == PASS == GFSX( +15 = 0x000F, 3, 1) =   -1 = 0xFFFFFFFF (wanted   -1 = 0xFFFFFFFF)
    == PASS == GFSX( +15 = 0x000F, 4, 2) =   +3 = 0x00000003 (wanted   +3 = 0x00000003)
    == PASS == GFSX( +15 = 0x000F, 5, 0) =  +15 = 0x0000000F (wanted  +15 = 0x0000000F)
    == PASS == GFSX( +15 = 0x000F, 5, 1) =   +7 = 0x00000007 (wanted   +7 = 0x00000007)
    == PASS == GFSX( +15 = 0x000F, 5, 2) =   +3 = 0x00000003 (wanted   +3 = 0x00000003)
    == PASS == GFSX( +15 = 0x000F, 5, 3) =   +1 = 0x00000001 (wanted   +1 = 0x00000001)
    == PASS == GFSX( +15 = 0x000F, 5, 4) =   +0 = 0x00000000 (wanted   +0 = 0x00000000)
    == PASS == GFSX(  +3 = 0x0003, 2, 0) =   +3 = 0x00000003 (wanted   +3 = 0x00000003)
    == PASS == GFSX(+243 = 0x00F3, 2, 0) =   +3 = 0x00000003 (wanted   +3 = 0x00000003)
    == PASS == GFSX(+243 = 0x00F3, 3, 0) =   +3 = 0x00000003 (wanted   +3 = 0x00000003)
    == PASS == GFSX(+243 = 0x00F3, 4, 0) =  -13 = 0xFFFFFFF3 (wanted  -13 = 0xFFFFFFF3)
    == PASS == GFSX(+243 = 0x00F3, 5, 0) =  -13 = 0xFFFFFFF3 (wanted  -13 = 0xFFFFFFF3)
    == PASS == GFSX(+243 = 0x00F3, 6, 0) =  -13 = 0xFFFFFFF3 (wanted  -13 = 0xFFFFFFF3)
    == PASS == GFSX(+243 = 0x00F3, 7, 0) =  -13 = 0xFFFFFFF3 (wanted  -13 = 0xFFFFFFF3)
    == PASS == GFSX(+243 = 0x00F3, 7, 1) =   -7 = 0xFFFFFFF9 (wanted   -7 = 0xFFFFFFF9)
    == PASS == GFSX(+243 = 0x00F3, 7, 2) =   -4 = 0xFFFFFFFC (wanted   -4 = 0xFFFFFFFC)
    == PASS == GFSX(+243 = 0x00F3, 7, 3) =   -2 = 0xFFFFFFFE (wanted   -2 = 0xFFFFFFFE)
    == PASS == GFSX(+243 = 0x00F3, 7, 4) =   -1 = 0xFFFFFFFF (wanted   -1 = 0xFFFFFFFF)
    == PASS == GFSX(+243 = 0x00F3, 8, 0) = +243 = 0x000000F3 (wanted +243 = 0x000000F3)
    == PASS ==
    
    Exhaustive test
           GFSX(1604336871 = 0x5FA03CE7,  1,  0) =         -1 = 0xFFFFFFFF
           GFSX(1604336871 = 0x5FA03CE7,  2,  0) =         -1 = 0xFFFFFFFF
           GFSX(1604336871 = 0x5FA03CE7,  2,  1) =         -1 = 0xFFFFFFFF
           GFSX(1604336871 = 0x5FA03CE7,  3,  0) =         +7 = 0x00000007
           GFSX(1604336871 = 0x5FA03CE7,  3,  1) =         +3 = 0x00000003
           GFSX(1604336871 = 0x5FA03CE7,  3,  2) =         +1 = 0x00000001
           GFSX(1604336871 = 0x5FA03CE7,  4,  0) =         +7 = 0x00000007
           GFSX(1604336871 = 0x5FA03CE7,  4,  1) =         +3 = 0x00000003
           GFSX(1604336871 = 0x5FA03CE7,  4,  2) =         +1 = 0x00000001
           GFSX(1604336871 = 0x5FA03CE7,  4,  3) =         +0 = 0x00000000
           GFSX(1604336871 = 0x5FA03CE7,  5,  0) =        -25 = 0xFFFFFFE7
           GFSX(1604336871 = 0x5FA03CE7,  5,  1) =        -13 = 0xFFFFFFF3
           GFSX(1604336871 = 0x5FA03CE7,  5,  2) =         -7 = 0xFFFFFFF9
           GFSX(1604336871 = 0x5FA03CE7,  5,  3) =         -4 = 0xFFFFFFFC
           GFSX(1604336871 = 0x5FA03CE7,  5,  4) =         -2 = 0xFFFFFFFE
           GFSX(1604336871 = 0x5FA03CE7,  6,  0) =        -25 = 0xFFFFFFE7
           GFSX(1604336871 = 0x5FA03CE7,  6,  1) =        -13 = 0xFFFFFFF3
           GFSX(1604336871 = 0x5FA03CE7,  6,  2) =         -7 = 0xFFFFFFF9
           GFSX(1604336871 = 0x5FA03CE7,  6,  3) =         -4 = 0xFFFFFFFC
           GFSX(1604336871 = 0x5FA03CE7,  6,  4) =         -2 = 0xFFFFFFFE
           GFSX(1604336871 = 0x5FA03CE7,  6,  5) =         -1 = 0xFFFFFFFF
    ...
           GFSX(1604336871 = 0x5FA03CE7, 29, 28) =         +1 = 0x00000001
           GFSX(1604336871 = 0x5FA03CE7, 30,  0) = -543146777 = 0xDFA03CE7
           GFSX(1604336871 = 0x5FA03CE7, 30,  1) = -271573389 = 0xEFD01E73
           GFSX(1604336871 = 0x5FA03CE7, 30,  2) = -135786695 = 0xF7E80F39
           GFSX(1604336871 = 0x5FA03CE7, 30,  3) =  -67893348 = 0xFBF4079C
           GFSX(1604336871 = 0x5FA03CE7, 30,  4) =  -33946674 = 0xFDFA03CE
           GFSX(1604336871 = 0x5FA03CE7, 30,  5) =  -16973337 = 0xFEFD01E7
           GFSX(1604336871 = 0x5FA03CE7, 30,  6) =   -8486669 = 0xFF7E80F3
           GFSX(1604336871 = 0x5FA03CE7, 30,  7) =   -4243335 = 0xFFBF4079
           GFSX(1604336871 = 0x5FA03CE7, 30,  8) =   -2121668 = 0xFFDFA03C
           GFSX(1604336871 = 0x5FA03CE7, 30,  9) =   -1060834 = 0xFFEFD01E
           GFSX(1604336871 = 0x5FA03CE7, 30, 10) =    -530417 = 0xFFF7E80F
           GFSX(1604336871 = 0x5FA03CE7, 30, 11) =    -265209 = 0xFFFBF407
           GFSX(1604336871 = 0x5FA03CE7, 30, 12) =    -132605 = 0xFFFDFA03
           GFSX(1604336871 = 0x5FA03CE7, 30, 13) =     -66303 = 0xFFFEFD01
           GFSX(1604336871 = 0x5FA03CE7, 30, 14) =     -33152 = 0xFFFF7E80
           GFSX(1604336871 = 0x5FA03CE7, 30, 15) =     -16576 = 0xFFFFBF40
           GFSX(1604336871 = 0x5FA03CE7, 30, 16) =      -8288 = 0xFFFFDFA0
           GFSX(1604336871 = 0x5FA03CE7, 30, 17) =      -4144 = 0xFFFFEFD0
           GFSX(1604336871 = 0x5FA03CE7, 30, 18) =      -2072 = 0xFFFFF7E8
           GFSX(1604336871 = 0x5FA03CE7, 30, 19) =      -1036 = 0xFFFFFBF4
           GFSX(1604336871 = 0x5FA03CE7, 30, 20) =       -518 = 0xFFFFFDFA
           GFSX(1604336871 = 0x5FA03CE7, 30, 21) =       -259 = 0xFFFFFEFD
           GFSX(1604336871 = 0x5FA03CE7, 30, 22) =       -130 = 0xFFFFFF7E
           GFSX(1604336871 = 0x5FA03CE7, 30, 23) =        -65 = 0xFFFFFFBF
           GFSX(1604336871 = 0x5FA03CE7, 30, 24) =        -33 = 0xFFFFFFDF
           GFSX(1604336871 = 0x5FA03CE7, 30, 25) =        -17 = 0xFFFFFFEF
           GFSX(1604336871 = 0x5FA03CE7, 30, 26) =         -9 = 0xFFFFFFF7
           GFSX(1604336871 = 0x5FA03CE7, 30, 27) =         -5 = 0xFFFFFFFB
           GFSX(1604336871 = 0x5FA03CE7, 30, 28) =         -3 = 0xFFFFFFFD
           GFSX(1604336871 = 0x5FA03CE7, 30, 29) =         -2 = 0xFFFFFFFE
    
    0 讨论(0)
  • 2021-01-23 11:23

    There are multiple approaches that you can take. If you were just starting out, you could just arithmetically calculate the number of bits in the field. So, for instance:

    if (value %2 >= 1)
    {
        // you know that the value has a `1` as the lest significant digit. 
        // if that's one of the digits you're looking for, you can do something like count++ here
    }
    else
    {
        // least significant digit is a '0'
    }
    

    and then

    if (value % 4 >=2)
    {
        // you know that the second least significant digit is `1`
        // etc.
    }
    

    If you do it that way, you'll probably want to work those into a loop of some sort.

    Now, a better way to do it is using bitwise anding, like this:

    if (value & 8 != 0)
        // here you know that the fourth least significant digit (the one representing 8) is 1.
        // do a Google search on bitwise anding to get more information.
    
    0 讨论(0)
提交回复
热议问题