void times(unsigned short int time)
{
hours=time>>11;
minutes=((time<<5)>>10);
}
time
设为24446
输出值
预期值
此代码中正在进行哪些内部处理?
24446
的二进制文件为0101111101111110
Time>>11
提供01011
,表示11
。
((Time<<5)>>10)
提供111011
,表示59
。
但是这里还发生了什么?
答案 0 :(得分:3)
这段代码似乎认为int
是16位,左移位时间将清除前5位。
由于您最有可能使用32/64位,如果time
中的值为16位值,则不会发生这种情况:
time >> 5 == (time << 5) >> 10
试试这个:
minutes = (time >> 5) & 0x3F;
或
minutes = (time & 0x07FF) >> 5;
或
将time
声明为unsigned short
,并在每次移位操作后强制转换为unsigned short
,因为数学是32/64位。
24446 in binary是:0101 1111 0111 1110
答案 1 :(得分:2)
这里还有什么?
如果time
为unsigned short
,则
minutes=((time<<5)>>10);
和
unsigned short temp = time << 5;
minutes = temp >> 10;
在两个表达式中,由于整数提升规则,time << 5
被计算为int
。 [注1和2]。
在第一个表达式中,此int
结果右移10。在第二个表达式中,对unsigned short temp
的赋值将结果缩小为short
,然后右移10点。
因此,在第二个表达式中,高阶位被移除(通过强制转换为unsigned short
),而在第一个表达式中,如果int
宽于{{1},则不会删除它们}}
第一个表达还有另一个重要的警告。由于整数提升可能会将short
更改为unsigned short
,因此中间值可能会被签名,在这种情况下,如果左移足够大,则可能出现溢出。 (在这种情况下,它不是。)然后可以将右移应用于负数,结果是“实现定义的”;许多实现将负数的右移行为定义为符号扩展数。这也可能导致意外。
注意:
假设int
宽于int
。如果short
和unsigned int
的宽度相同,则不会进行转换,您也不会看到所描述的差异。 “整数促销”在C标准的§6.3.1.1/ 2中描述(使用C11草案):
如果
unsigned short
可以表示原始类型的所有值(由宽度限制,对于a 位字段),该值转换为int
;否则,它将转换为int
。这些被称为整数促销。所有其他类型都没有改变 整数促销。
整数提升规则有效地使得无法使用小于unsigned
int
的类型直接进行任何算术计算,尽管编译器可能会使用int
规则来使用子字操作码。在这种情况下,它们必须产生与促进价值产生的结果相同的结果;这对于无符号加法和乘法很容易,但对于移位来说比较棘手。
bitshift运算符是算术运算语义的一个例外。对于大多数算术运算,C标准要求在执行操作之前应用“通常的算术转换”。通常的算术转换,除其他外,保证两个操作数具有相同的类型,这也是结果的类型。对于位移,标准仅要求对两个操作数执行整数提升,并且结果将具有左操作数的类型。那是因为移位运算符不对称。对于几乎所有的体系结构,没有有效的右操作数用于不适合无符号字符的移位,并且显然不需要左右操作数的类型甚至签名都是相同的。
无论如何,与所有算术运算符一样,将执行整数提升(至少)。因此,您不会看到比what-if
更窄的中间结果。
答案 2 :(得分:0)
对于使用32位的平台,似乎'int'的大小。 就处理而言,假设, 第一个陈述是将“时间”除以“11”。 第二个陈述是将“时间”乘以5然后将整数除以10。 你的问题的答案在这里结束。
如果您添加实际包含的时间值(秒数/毫秒/小时或其他),那么您可能会获得更多帮助。
编辑: 正如@egur指出的那样,您可能正在将代码从16位移植到32/64位平台。 一种广泛接受的C编码风格使代码可移植如下:
制作Typedef.h文件并将其包含在每个其他C文件中,
//Typedef.h
typedef unsigned int U16
typedef signed int S16
typedef unsigned short U8
typedef signed short S8
:
:
//END
在声明变量时使用U16,U8等。
现在当您移动到更大的位处理器(例如32位)时,请将Typedef.h更改为
//Typedef.h
typedef unsigned int U32
typedef signed int S32
typedef unsigned short U16
typedef signed short S16
无需在休息代码中更改任何内容。
EDIT2:
看到你的编辑后:
((Time<<5)>>10) gives 111011 which means 59.
对于32位处理器
((Time<<5)>>10) gives 0000 0010 1111 1011 which means 763.