VTi*_*Tux 18 c implicit-conversion
使用我的编译器,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;
Run Code Online (Sandbox Code Playgroud)
是否可以选择提醒这些案件?
Wconversion警告:
void foo(unsigned long a);
foo(a+b);
Run Code Online (Sandbox Code Playgroud)
但没有警告:
unsigned long c = a + b
Run Code Online (Sandbox Code Playgroud)
too*_*ite 16
首先,您应该知道在C中标准类型没有标准整数类型的特定精度(可表示值的数量).它只需要每种类型的最小精度.这些导致以下典型的位大小,标准允许更复杂的表示:
char:8位short:16位int:16(!)位long:32位long long (自C99起):64位注意:实现中给出了实现的实际限制(这意味着一定的精度)limits.h.
其次,执行操作的类型由操作数的类型决定,而不是赋值左侧的类型(因为赋值也只是表达式).为此,上面给出的类型按转换等级排序.排名较小的操作数int将转换为int第一个.对于其他操作数,具有较小等级的操作数将转换为另一个操作数的类型.这些是通常的算术转换.
您的实现似乎使用unsigned int与相同大小的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;
Run Code Online (Sandbox Code Playgroud)
或者,使用已知大小的类型:
#include <stdint.h>
...
uint16_t a = 60000, b = 60000;
uint32_t c = (uint32_t)a + b;
Run Code Online (Sandbox Code Playgroud)
请注意,由于转换规则,转换一个操作数就足够了.
更新(感谢@chux):
上面显示的演员没有问题.但是,如果a转换排名大于类型转换,则可能会将其值截断为较小的类型.虽然这很容易避免,因为所有类型在编译时都是已知的(静态类型),但另一种方法是乘以所需类型的1:
unsigned long c = ((unsigned long)1U * a) + b
Run Code Online (Sandbox Code Playgroud)
这样,使用了演员阵容或a(或b)中给出的较大等级.任何合理的编译器都会消除乘法.
另一种避免甚至不知道目标类型名称的方法可以通过typeof()gcc扩展来完成:
unsigned long c;
... many lines of code
c = ((typeof(c))1U * a) + b
Run Code Online (Sandbox Code Playgroud)
a + b将被计算为unsigned int(分配给a的事实unsigned long不相关).C标准的任务,这个总和将环绕模"一加最大的无符号的可能".在您的系统上,它看起来像是unsigned int16位,因此结果以模数65536计算.
在另一个系统上,它看起来像int和unsigned int更大,因此能够容纳更大的数字.现在发生的事情非常微妙(承认@PascalCuoq):因为所有的值unsigned short都可以表示int,a + b将被计算为int.(仅当short和int具有相同的宽度,或者在一些其它方式中,一些值unsigned short不能被表示为int将总和将被计算为unsigned int).
虽然C标准没有为a unsigned short或an 指定固定大小unsigned int,但是您的程序行为是明确定义的.请注意,对于签名类型,情况并非如此.
作为最后的话,你可以使用大小类型uint16_t,uint32_t等等,如果你的编译器的支持,都保证有指定的大小.