不同大小的数字可以是10位或12位或15位。我想签名扩展立即位,以便16位整数具有与10,12或15位值相同的值。
修改的
对不起,我没有发布我写的代码,这是行不通的。这是:
switch (instr):
{
case IMMI_10:
int bits_to_cover = 16 - 10;
signed short amount = (instr & 15);
if (amount & (1 << bits_to_cover >> 1))
{
amount -= 1 << bits_to_cover;
}
break;
case IMMI_12:
int bits_to_cover = 16 - 12;
signed short amount = (instr & 15);
if (amount & (1 << bits_to_cover >> 1))
{
amount -= 1 << bits_to_cover;
}
break;
case IMMI_15:
int bits_to_cover = 16 - 15;
signed short amount = (instr & 15);
if (amount & (1 << bits_to_cover >> 1))
{
amount -= 1 << bits_to_cover;
}
break;
}
这是在为学校的CSE课程建造的特殊机器上运行的。它没有运行x86架构。它被称为CSE 410机器。文档:https://courses.cs.washington.edu/courses/cse410/18sp/410machine/isaManual.html
答案 0 :(得分:3)
我的工作基础是,例如,如果您将10位数字符号扩展为16位,那么您需要考虑两种情况:
zzzzzz1x xxxxxxxx
zzzzzz0x xxxxxxxx
x&#34;不关心 - 必须复制&#34;结果中的位。领先的z&#34;不关心 - 将覆盖&#34;位。在两个示例中,在0和1之间切换的位是符号位,必须将其复制到显示为前导z的位置。我还假设这些位从0(最低有效位或LSB)到15(最高有效位或MSB)编号。如果您需要对1到16位进行编号,那么您需要进行一些调整。
给定函数签名:
uint16_t sign_extend(uint16_t value, uint16_t bits)
我们可以通过以下方式确定符号位:
uint16_t sign = (1 << (bits - 1)) & value;
我们可以使用正位(0)符号位0扩展一个值,并使用位掩码对该值进行扩展:
00000001 11111111
我们可以通过负位(1)符号位1扩展一个值,或者使用位掩码对该值进行扩展:
11111110 00000000
在下面的代码中,我使用:
生成第二个掩码uint16_t mask = ((~0U) >> (bits - 1)) << (bits - 1);
并使用逐位反转生成另一个。
该代码避免了对右移右值时会发生什么的假设。 (参见comment samgak。)C标准说这是实现定义的行为,通常的情况是将MSB(符号)位复制到空出的位中。 (也称算术右移)或&#39;将空出位设置为零&#39; (又名逻辑右移)。两者都是允许的,但给定的编译器必须使用其中一个。无论编译器做什么,此代码都将起作用,因为它避免了右移有符号数量。 (为了弥补这一点,它假设你可以将有符号整数分配给相应的无符号整数类型,反之亦然,即使有符号值是负数。正式地,标准只要求对公共值的子集起作用 - 来自0到<signed-type>_MAX
,但是我没有听说过这个问题的系统,而我已经听说过系统处理换档的方式不同。)
将所有内容放在一起,这是我在测试工具中使用的功能:
#include <assert.h>
#include <stdint.h>
extern uint16_t sign_extend(uint16_t value, uint16_t bits);
uint16_t sign_extend(uint16_t value, uint16_t bits)
{
assert(bits > 0 && bits < 16);
uint16_t sign = (1 << (bits - 1)) & value;
uint16_t mask = ((~0U) >> (bits - 1)) << (bits - 1);
if (sign != 0)
value |= mask;
else
value &= ~mask;
return value;
}
#ifdef TEST
#include <stdio.h>
struct TestSignExtend
{
uint16_t value;
uint16_t bits;
uint16_t result;
};
static int test_sign_extend(const struct TestSignExtend *test)
{
uint16_t result = sign_extend(test->value, test->bits);
const char *pass = (result == test->result) ? "** PASS **" : "== FAIL ==";
printf("%s: value = 0x%.4X, bits = %2d, wanted = 0x%.4X, actual = 0x%.4X\n",
pass, test->value, test->bits, test->result, result);
return(result == test->result);
}
int main(void)
{
struct TestSignExtend tests[] =
{
{ 0x0123, 10, 0x0123 },
{ 0x0323, 10, 0xFF23 },
{ 0x0323, 11, 0x0323 },
{ 0x0723, 11, 0xFF23 },
{ 0x0323, 12, 0x0323 },
{ 0x0C23, 12, 0xFC23 },
{ 0x0323, 13, 0x0323 },
{ 0x1723, 13, 0xF723 },
{ 0x1323, 14, 0x1323 },
{ 0x3723, 14, 0xF723 },
{ 0x0323, 15, 0x0323 },
{ 0xC723, 15, 0xC723 },
{ 0x0123, 9, 0xFF23 },
{ 0x0223, 9, 0x0023 },
{ 0x0129, 8, 0x0029 },
{ 0x03E9, 8, 0xFFE9 },
};
enum { NUM_TESTS = sizeof(tests) / sizeof(tests[0]) };
int pass = 0;
for (int i = 0; i < NUM_TESTS; i++)
pass += test_sign_extend(&tests[i]);
if (pass == NUM_TESTS)
printf("PASS - All %d tests passed\n", NUM_TESTS);
else
printf("FAIL - %d tests failed out of %d run\n", NUM_TESTS - pass, NUM_TESTS);
return(pass != NUM_TESTS); /* Process logic is inverted! */
}
#endif /* TEST */
示例输出:
** PASS **: value = 0x0123, bits = 10, wanted = 0x0123, actual = 0x0123
** PASS **: value = 0x0323, bits = 10, wanted = 0xFF23, actual = 0xFF23
** PASS **: value = 0x0323, bits = 11, wanted = 0x0323, actual = 0x0323
** PASS **: value = 0x0723, bits = 11, wanted = 0xFF23, actual = 0xFF23
** PASS **: value = 0x0323, bits = 12, wanted = 0x0323, actual = 0x0323
** PASS **: value = 0x0C23, bits = 12, wanted = 0xFC23, actual = 0xFC23
** PASS **: value = 0x0323, bits = 13, wanted = 0x0323, actual = 0x0323
** PASS **: value = 0x1723, bits = 13, wanted = 0xF723, actual = 0xF723
** PASS **: value = 0x1323, bits = 14, wanted = 0x1323, actual = 0x1323
** PASS **: value = 0x3723, bits = 14, wanted = 0xF723, actual = 0xF723
** PASS **: value = 0x0323, bits = 15, wanted = 0x0323, actual = 0x0323
** PASS **: value = 0xC723, bits = 15, wanted = 0xC723, actual = 0xC723
** PASS **: value = 0x0123, bits = 9, wanted = 0xFF23, actual = 0xFF23
** PASS **: value = 0x0223, bits = 9, wanted = 0x0023, actual = 0x0023
** PASS **: value = 0x0129, bits = 8, wanted = 0x0029, actual = 0x0029
** PASS **: value = 0x03E9, bits = 8, wanted = 0xFFE9, actual = 0xFFE9
PASS - All 16 tests passed
在所有事情都先通过之后,我确实在其中一个测试中犯了一个故意错误,只是为了确保发现失败。
在您的代码中,您可以像这样使用它:
signed short value = …;
switch (instr):
{
case IMMI_10:
value = sign_extend(value, 10);
break;
case IMMI_12:
value = sign_extend(value, 12);
break;
case IMMI_15:
value = sign_extend(value, 15);
break;
default:
assert(0 && "can't happen!");
}
如果案例标签IMMI_10
,IMMI_12
和IMMI_15
的值为10
,12
,15
,那么您可以避免切换并简单地使用作业:
signed short value = …; // Get the value from somewhere
value = sign_extend(value, instr);