C中的整数除法与无符号短整数

时间:2017-11-29 11:15:11

标签: c arrays integer division

我觉得最血腥的初学者 - 为什么以下不起作用:

// 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上的长度不同。

欢呼,斯蒂芬

3 个答案:

答案 0 :(得分:1)

问题在于:

addr[1] = (~currentAddr)/2+1;

您希望currentAddr0xFFFF,这是部分正确的。但是,你可能错过的是整数提升规则,它使0xFFFFFFFF成为-1的十六进制表示。

现在,有一个简单的数学: (~currentAddr)/2+1只是0x011,当您~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,因此值/类型首先会提升为intunsigned。在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)