使用我的编译器,c为54464 (16位截断),d为10176。但是对于gcc,c是120000,d是600000。
真正的行为是什么?行为不明确吗?还是我的编译器是假的?
unsigned short a = 60000;
unsigned short b = 60000;
unsigned long c = a + b;
unsigned long d = a * 10;是否有办法对这些案件发出警报?
对以下事项发出警告:
void foo(unsigned long a);
foo(a+b);但并没有警告:
unsigned long c = a + b发布于 2015-07-27 12:16:40
首先,您应该知道,在C中,标准类型对于标准整数类型没有特定的精度(可表示值的数目)。它只需要对每种类型的最小精度。这些结果导致了以下典型的位大小,标准允许更复杂的表示:
char:8位short:16位int:16 (!)比特long:32位long long (自C99):64位注意:在limits.h中给出了实现的实际限制(这意味着一定的精度)。
第二,执行操作的类型取决于操作数的类型,而不是赋值左侧的类型(因为赋值也只是表达式)。为此,上面给出的类型按转换等级排序。秩小于int的操作数首先被转换为int。对于其他操作数,级别较小的操作数转换为另一个操作数的类型。这些是常用算术变换。
您的实现似乎使用了与unsigned short相同大小的16位unsigned short,因此a和b被转换为unsigned int,操作以16位执行。对于unsigned,该操作执行模块65536 (2到16的幂)--这称为环绕(这是而不是签名类型所需的!)。然后将结果转换为unsigned long并分配给变量。
对于gcc来说,我认为这是为PC或32位CPU编译的。为此,(unsigned) int通常有32位,而(unsigned) long至少有32位(必需)。因此,这些操作没有包装。
注意:对于PC,操作数被转换为int,而不是unsigned int。这是因为int已经可以表示unsigned short的所有值;不需要unsigned int。这可能导致意外的(实际上:实现定义的)行为,如果操作的结果溢出signed int!
如果需要定义大小的类型,请参见stdint.h (自C99)中的uint16_t、uint32_t。这些是具有适合您的实现的适当大小的类型的typedef。
您还可以强制转换一个操作数(不是整个表达式!)对结果的类型:
unsigned long c = (unsigned long)a + b;或者,使用已知大小的类型:
#include <stdint.h>
...
uint16_t a = 60000, b = 60000;
uint32_t c = (uint32_t)a + b;注意,由于转换规则,转换一个操作数就足够了。
更新(感谢@chux):
上面所示的铸造没有问题。但是,如果a的转换级别大于类型广播,则可能会将其值截断为较小的类型。虽然可以很容易地避免这种情况,因为所有类型都是在编译时已知的(静态类型),另一种方法是用所需类型中的一个进行乘法:
unsigned long c = ((unsigned long)1U * a) + b这样,就可以使用cast或a (或b)中给出的类型的更大级别。任何合理的编译器都会消除乘法运算。
另一种方法,即使不知道目标类型名称,也可以使用typeof() gcc扩展来完成:
unsigned long c;
... many lines of code
c = ((typeof(c))1U * a) + b发布于 2015-07-27 12:05:44
a + b将被计算为unsigned int (分配给unsigned long的事实与此无关)。C标准要求这个和将围绕模“1加上最大的无符号可能”。在您的系统上,它看起来像一个unsigned int是16位,所以结果是计算模块65536。
在另一个系统中,int和unsigned int看起来更大,因此能够容纳更大的数字。现在发生的事情非常微妙(确认@PascalCuoq):因为unsigned short的所有值在int中都是可表示的,a + b将被计算为int。(只有当short和int具有相同的宽度,或者以其他方式不能将unsigned short的某些值表示为int时,才会将和计算为unsigned int。)
尽管C标准没有为unsigned short或unsigned int指定固定大小,但您的程序行为是很好定义的。但请注意,对于有符号类型,这是而不是 true。
最后,您可以使用uint16_t、uint32_t等大小类型,这些类型如果得到编译器的支持,则保证具有指定的大小。
发布于 2015-07-27 16:26:44
在C中,char、short (及其无符号耦合器件)和float类型应该被视为“存储”类型,因为它们是为优化存储而设计的,但不是CPU所喜欢的“本地”大小,而从不用于计算。
例如,当您有两个char值并将它们放在表达式中时,首先将它们转换为int,然后执行操作。原因是CPU在int中工作得更好。对于总是隐式转换为double以进行计算的double,也会发生同样的情况。
在您的代码中,计算a+b是两个无符号整数的和;在C中,无法计算两个无符号短路的和。您可以做的是将存储在一个没有签名的短消息中,最后结果,由于模块化数学的特性,它将是相同的。
https://stackoverflow.com/questions/31652572
复制相似问题