我觉得最血腥的初学者 - 为什么以下不起作用:
// declarations
unsigned short currentAddr= 0x0000;
unsigned short addr[20] = {1, 0};
// main
addr[1] = (~currentAddr)/2+1;
printf("addr[1] wert: %hu\n", addr[1]); // equals 1, expecte 0x8000
addr[1] = ~currentAddr>>1;
printf("addr[1] wert: %hu\n", addr[1]); // equals 65535, expected 0x7FFF
在printf和我的调试器监视列表中,addr [1]的值不符合预期。我的目标是获得变量的最大值的一半,这里是0x8000。 信息:我正在做〜currentAddr以获得最大值。 0xFFFF,如果我的嵌入式平台上的短路长度与我的PC上的长度不同。
欢呼,斯蒂芬答案 0 :(得分:1)
问题在于:
addr[1] = (~currentAddr)/2+1;
您希望currentAddr
到0xFFFF
,这是部分正确的。但是,你可能错过的是整数提升规则,它使0xFFFFFFFF
成为-1
的十六进制表示。
现在,有一个简单的数学:
(~currentAddr)/2+1
只是0x01
或1
,当您~currentAddr>>1;
执行此转变时,它会再次成为-1
。
这
我的目标是将变量的最大值的一半设为
0x8000
如果我理解正确,你要做的就是得到等于(无符号短路的最大值)/ 2的值。如果是这样,正确的方法是使用USHRT_MAX
。当然,您需要在源代码中包含limits.h
文件。
<强>更新强>
请参阅您对David回答的评论,以下更改按预期进行。 (你已经测试过了,我还没有)
unsigned short c;
c = ~currentAddr;
unsigned short c_z = sizeof (c);
unsigned short ci;
ci = (c >> 1) + 1;
unsigned short ci_z = sizeof (ci);
addr[1] = ci;
现在,为什么这不会被提升为整数而不是之前的情况
c = ~currentAddr;
它被提升了,但它产生了预期的结果,因为,正如chux所解释的那样(我无法做到),它在其操作期间(暂时)被提升为int
,但被解析为(已转换) to)a unsigned short
当它存储在分配给c
的内存中时。
C标准回答了这个问题:
根据C99标准:6.5.16.1简单分配
在简单赋值(=)中,右操作数的值将转换为赋值表达式的类型,并替换存储在左操作数指定的对象中的值。 在您的情况下,由于LHS和RHS属于同一类型,因此无需进行任何转换。
另外,它说:
赋值表达式的类型是左值操作数在左值转换后的类型。
同样由 C11 6.5.16.1/2:
指定在简单赋值(=)中,右操作数的值将转换为赋值表达式的类型,并替换存储在左操作数指定的对象中的值。
亲自试试:
int main(void)
{
unsigned short c;
unsigned short currentAddr= 0x0000;
c = ~currentAddr;
printf("\n0x%x", c);
printf("\n0x%x", (~currentAddr));
return 0;
}
这应该打印:
0xffff
0xffffffff
答案 1 :(得分:1)
addr[1] = (~currentAddr)/2+1;
让我们将其细分:currentAddr
是计算中涉及的unsigned short
,因此值/类型首先会提升为int
或unsigned
。在C中,这是整数提升。
如果
int
可以表示原始类型的所有值...,则该值将转换为int;否则,它将转换为unsigned int
。这些被称为整数促销。整数促销不会更改所有其他类型。 C11dr§6.3.1.12
当USHRT_MAX <= INT_MAX
时,(例如16位短整数/无符号,32位整数/无符号),代码如下所示。使用currentAddr == 0
和典型的2的补码行为,~0 - &gt; -1和addr[1]
- &gt; 1。
int tmp = currentAddr;
addr[1] = (~tmp)/2+1;
当USHRT_MAX > INT_MAX
时,(例如16位短整数/无符号,16位整数/无符号),代码如下所示。使用currentAddr == 0
和无符号行为,~0 - &gt; 0xFFFF和addr[1]
- &gt;为0x8000。
unsigned tmp = currentAddr;
addr[1] = (~tmp)/2+1;
我的目标是获得变量
的最大值的一半
获取unsigned short
最大值的最佳方法是使用SHRT_MAX
并跳过~
代码。无论unsigned short, int, unsigned
范围如何,它都可以按预期工作。它还可以更好地记录代码意图。
#include <limits.h>
addr[1] = USHRT_MAX/2+1;
答案 2 :(得分:0)
因为数字2是int而int可以保持unsigned short,所以实际操作是addr[1] = (unsigned short)(((int)(~currentAddr)/2)+1)