C 什么是;较宽范围内的精度较低”;警告到底是什么意思?
我有以下代码,用于int为16位、long int为32位的嵌入式平台:C 什么是;较宽范围内的精度较低”;警告到底是什么意思?,c,compiler-warnings,precision,C,Compiler Warnings,Precision,我有以下代码,用于int为16位、long int为32位的嵌入式平台: #define MULTIPLIER 0x1000 static void my_function(uint16_t i, void *p) { uint32_t start = MULTIPLIER * i; ... } 我的编译器向我发出警告: Warning 1 : lower precision in wider context: '*' 这一行 这到底意味着什么?我可以通过将#define改
#define MULTIPLIER 0x1000
static void my_function(uint16_t i, void *p)
{
uint32_t start = MULTIPLIER * i;
...
}
我的编译器向我发出警告:
Warning 1 : lower precision in wider context: '*'
这一行
这到底意味着什么?我可以通过将#define改为
#define MULTIPLER 0x1000ul
(明确地将其设为无符号长)但我想理解警告 我认为该警告意味着您可能需要一个32位的结果,但由于
0x1000
具有typeint
和I
具有typeint16\t
,表达式仅为typeint
,可能会溢出,而不会给出所需的结果。我认为警告意味着您可能需要32位结果,但由于0x1000
具有typeint
和I
具有typeint16\u t
,因此,表达式仅为int
类型,可能会溢出,无法提供所需的结果。它警告您,乘法将使用16位值进行,然后16位结果将转换为32位结果。这可能不是您所期望的(16位乘法可能会溢出),因此发出警告
涵盖该问题它警告您,乘法将使用16位值进行,然后16位结果将转换为32位结果。这可能不是您所期望的(16位乘法可能会溢出),因此发出警告
涵盖表达式
乘数*i
的问题编译器从操作数类型中选择精度更高的类型。在第一种情况下,您给它两个int
s,这意味着您将得到一个截断的结果,之后将转换为long int
,但精度仍然是16位
在后一种情况下,显式地使一个操作数变长,然后将结果写入相同精度的变量 对于表达式
乘数*i
,编译器从操作数类型中选择精度更高的类型。在第一种情况下,您给它两个int
s,这意味着您将得到一个截断的结果,之后将转换为long int
,但精度仍然是16位
在后一种情况下,显式地使一个操作数变长,然后将结果写入相同精度的变量 虽然这听起来似乎有道理,但我相信你错了。我非常确定乘法是在32位寄存器(在i386上)中完成的,而不考虑16位声明。结果将放置在32位目标中,因此不会截断。我认为问题在于签名与未签名的冲突,但我必须查看asm代码才能确定。PS:我不认为这是一个溢出警告,因为这是一个运行时的事情。16位*16位可能溢出,也可能不溢出,这取决于操作数值。@Hotei:你错了,原因有很多。(1) 这不是i386,而是一些未指定的16位嵌入式环境。在这种情况下,C需要将结果截断为16位。我对Macintosh C编译器的一个主要不满是,尽管68000只有一条16x16->32乘法指令,在C语言中没有编写16x16->32乘法的好方法。编译器会不遗余力地截断乘法指令的结果,除非其中一个操作数被强制转换为long,在这种情况下,它会浪费时间进行long*long乘法。在8位嵌入式系统上,我有时使用自己的乘法和除法例程;我最喜欢的是ldivmod,它将一个全局long除以一个8位值,得到一个8位结果。@R..:我想说的是,C(IIRC)将操作数转换为其最宽的操作数,即16位*32位将以32位精度完成。如果我们假设C是“最近”实现,那么#define MULTIPLIER 0x1000将被解释为int,ie 32位签名。将无符号16位和有符号32位的结果填充到无符号32位中将是(未定义的),这是编译器试图针对公认的模糊错误消息提出的建议。就像我说的,我需要看看asm,看看这是否真的发生了。实施方式差别很大。@Hotei:请重新阅读问题
int
在这个平台上是16位的,所以两个操作数都是16位的。虽然这听起来似乎有道理,但我相信你错了。我非常确定乘法是在32位寄存器(在i386上)中完成的,而不考虑16位声明。结果将放置在32位目标中,因此不会截断。我认为问题在于签名与未签名的冲突,但我必须查看asm代码才能确定。PS:我不认为这是一个溢出警告,因为这是一个运行时的事情。16位*16位可能溢出,也可能不溢出,这取决于操作数值。@Hotei:你错了,原因有很多。(1) 这不是i386,而是一些未指定的16位嵌入式环境。在这种情况下,C需要将结果截断为16位。我对Macintosh C编译器的一个主要不满是,尽管68000只有一条16x16->32乘法指令,在C语言中没有编写16x16->32乘法的好方法。编译器会不遗余力地截断乘法指令的结果,除非其中一个操作数被强制转换为long,在这种情况下,它会浪费时间进行long*long乘法。在8位嵌入式系统上,我有时使用自己的乘法和除法例程;我最喜欢的是ldivmod,它将一个全局long除以一个8位值,得到一个8位结果。@R..:我想说的是,C(IIRC)将操作数转换为其最宽的操作数,即16位*32位将以32位精度完成。如果我们假设C是“最近”实现,那么#define MULTIPLIER 0x1000将被解释为int,ie 32位签名。将无符号16位和有符号32位的结果填充到无符号32位将是(未定义的),这是编译器正在尝试的