Вход Расширение int в C

Так что у меня возникли проблемы с получением поля типа int и последующим подписанием его расширения. У меня есть метод, который получает поле Int.

getField(int value, int hi, int lo);

Значение - это int, из которого я беру поле, а hi и lo - размер поля.

Так что я могу вызвать этот метод getField внутри getFieldSignExtended(int value, int hi, int lo), но как мне пойти на знак расширения его?

например value = 7, hi = 1, lo = 0

getField(7, 1, 0); возвращает 3, потому что 7 в двоичном виде - это 111, а hi и lo принимают поле от 0 до 1.

При возвращении 3 из getField я получаю, что значение равно 0x0003.

То, что у меня есть, работает с позитивами, но сильно портит негативы. И когда я говорю "испортить", я имею в виду, что это не работает вообще. Так что, если я попытаюсь использовать его на -1, он будет показан как большой int вместо отрицательного.

Спасибо за любую помощь!:]

Изменить: Извините, я перепутал себя и некоторых из вас с противоречивым утверждением:P. Исправлена.

2 ответа

Здесь очень много чтения между строк. Однако если getField(7, 1, 0) возвращает 3 и вам нужно getFieldSignExtended(15, 2, 0) возвращать -3 а также getFieldSignExtended(3, 2, 0) возвращать +3, тогда это может быть то, что вы после.

Концепция заключается в том, что вы рассматриваете n-битное поле из битов hi:lo исходного значения как число дополнения до 2. Если первый бит из n битов равен 1, то вы хотите, чтобы n-битное поле рассматривалось как отрицательное число. Если первый бит 3-битного поля равен 0, то вы хотите, чтобы он рассматривался как положительное число.

#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);
}

3 утверждения являются прямыми; единственный спорный вопрос - код отказывается работать с битом 31. Если вы вызвали его с hi = 31 и lo = 0, то сдвиг (hi - lo + 1) слишком велик и поведение не определено. Вы также сталкиваетесь с поведением, определяемым реализацией правого смещения отрицательного числа. Можно было бы решить эти проблемы, используя целочисленный аргумент без знака и не & операция, если hi - lo + 1 == INT_BITS, Решение проблем оставлено в качестве упражнения для читателя.

Назначение bits сдвигает значение вправо и маскирует его с правильным количеством битов. (1 << (hi - lo + 1)) - 1 сдвиг 1 влево на единицу больше, чем число битов в поле, затем вычитает единицу, чтобы сгенерировать строку двоичных единиц для каждой позиции бита в поле. Например, для hi = 2, lo = 0, это сдвиг 1 в 3 места, дает двоичный 1000; вычитание 1 дает 0111, поэтому выбираются правильные 3 бита. Так, bits содержит соответствующий набор битов для n-битного целого числа.

if test проверяет, установлен ли старший значащий бит n-битного целого числа. Если бит знака не установлен, мы просто возвращаем значение bits, Если бит знака установлен, то у нас есть сложный расчет, который был (очень) неверен в первом наброске этого ответа. Предположим, что у нас есть поле 3 бита = 101. Как 3-битное число дополнения 2, которое представляет -3. Нам нужно расширить это влево со всеми 1, чтобы сгенерировать полный размер -1, Значение ~0 все биты 1; когда это сдвинуто влево hi - lo биты, он оставляет серию нулей для незнаковых битов значения. Это также будет работать, если вы переместитесь влево на hi - lo + 1, но есть дополнительные вычисления, необходимые для + 1 это не обязательно.

Я использовал этот тестовый комплект, чтобы убедиться, что код работает правильно. Систематический тестовый вывод является строгим (для небольших чисел). Это гарантирует, что расчетное значение соответствует ожидаемому значению. "Исчерпывающий" тест на самом деле не является исчерпывающим; он проверяет только одно значение и больше для наблюдения за проблемами (например, использование hi = 31 и lo = 0 дает ошибочный ответ 0 на моем компьютере) и шаблонов.

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);
}

Это вывод тестового кода перед исчерпывающим тестом, плюс небольшой выбор вывода из исчерпывающего теста:

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

Есть несколько подходов, которые вы можете использовать. Если вы только начинаете, вы можете просто арифметически рассчитать количество битов в поле. Так, например:

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'
}

а потом

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

Если вы сделаете это таким образом, вы, вероятно, захотите объединить их в какой-то цикл.

Теперь, лучший способ сделать это - использовать побитовый андинг, например так:

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.
Другие вопросы по тегам