有很多可怕的行會在這裏閱讀之間。但是,如果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比字段中的位數多1,然後減1,爲字段中的每個位位置生成一串二進制1。例如,對於hi = 2,lo = 0,這將左移3個位置,產生二進制1000;減1會得到0111,所以選擇正確的3位。因此,bits
包含適當的n位整數位。
if
測試檢查是否設置了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
「符號擴展用零」是自相矛盾的。 '符號擴展'表示'將符號位(0或1)複製到擴展名';只用零來擴展它,如果類型是無符號和擴展的話會發生什麼。 –
您的問題未指定,因此有可能被標記爲「關閉」爲「不是真正的問題」。另外,你嘗試過什麼方法? – Kaz
你的例子中的符號擴展可能意味着返回-1,因爲如果我們從'... 0000111'中取出'11'位,我們必須將'11'解釋爲一個兩位二進制補碼值,它代表-1 。在C中,在一個二進制補碼平臺上,一個帶符號的結構/聯合位域是兩位寬,其中保存「11」的結果爲-1。 – Kaz