提问人:Trashman 提问时间:5/3/2022 最后编辑:Trashman 更新时间:5/4/2022 访问量:104
在 c 中是否明确定义了在不同大小变量之间执行按位 OR 运算符并从较小的 uint 中减去较大的 uint 的行为?
Is behavior clearly defined in c for doing a bitwise OR operator between different size variables and subtracting a larger uint from a smaller uint?
问:
我试图弄清楚 c 中以下命令的最终结果是什么,以及可能更好的方法是什么。
这是我的变量。所有这些都是无符号整数,类型为 或uint16
uint32
CNT_A
:这是一个 *,但表示微处理器中的 16 位读/写计数器寄存器。它直接指向此寄存器的地址,因此它始终包含寄存器中的值。它由处理器自动递增,但可以由程序重置或写入设定值。从制造商的文档来看,上面的 16 位是“保留”的,因此,我相信,总是报告并且实际上不会被写入,所以它实际上是一个 16 位值。uint32
0
*NOTE: `CNT_A` is always called as a `uint32` in the code, but it is declared as a union of a `uint32` and a 32-bit `bitfield`, with the upper 16 bits of the bitfield unused.
update_counter
:这是一个“易失性 uint16”,每当调用该函数时,它就会在另一个函数中递增。
detect_pulse
如果在系统中检测到脉冲,则为 TRUEboolean
ignore_time
是一个 const uint16
wTempA
:这是从中提取 16 位计数器值的 auint16
REG_A
lwTempB
:这是一个 (=),用作存储两个 16 位值的临时变量,但涉及 32 位计算uint32
l
long
lwTempC
:这是用于通过其他变量的差异来检测变化的uint32
'lwLastA':这是一个静态值,用于存储函数的最终值并将其带到函数的下一次调用,并与新的uint32
lwTempA
lwTempA
以下是函数中相关的实际代码片段(请注意,显示的注释是我为这篇文章添加的注释,而不是在实际文件中):
void changeHandler(void) {
wTempA = REG_A; //Assigning a uint32 to a uint16, but upper 16 bits of uint32 are always 0
lwTempB = update_counter; //Assigning a uint16 to a uint32
lwTempB <<= 16; //Shifting uint16 value to upper 16 bits
lwTempB |= wTempA //Doing a logical OR of a uint16 with a uint32, then storing back to that uint32
...
if (detect_pulse)
{
lwLastA = wTempA //Setting "previous" value to wTempA if a pulse was detected
}
lwtempC = lwTempB - lwLastA //Subtracting uint16 from a uint32
if (lwTempC <= ignore_time) //There must be a significant difference to perform the following actions
{
return;
}
//...perform important actions with micro... (redacted)
...
lwLastA = wTempA //Setting previous value of wTempA
}
我从以前的程序员那里继承了这个函数。这不是我会做的方式,但如果没有必要,我不想重写整个事情。
我认为,如果出现以下两种情况之一,该函数应该触发“重要操作”。一种是如果发生导致递增的外部事件,另一种是如果经过的时间超过 。update_counter
ignore_time
上述每条线的所有预期行为是否都明确定义,是否会产生一致的结果?
我有几个具体的担忧:
是否明确定义了 lwTempB (uint32) 和 wTempA (uint16) 之间的按位 OR 将比较较低的 16 位。
update_counter
将在经过一定时间后滚动(除非有问题,否则它计数的事件以设定的频率发生),在该滚动点,lwLastA 实际上将大于 lwTempB。这里是否有明确定义的行为,其中两个无符号整数以通常会产生负结果的方式减去,然后将其分配给无符号整数?从布尔数学来看,我认为这将导致 lwTempC 的值总是大于 ignore_time 因此仍然会导致触发,所以草率的编码仍然应该提供所需的结果吗?
答:
有实现定义的行为。这意味着,C 语言不定义行为,但您的实现(编译器和标准库)必须定义。
在整数运算中,两端都提升为 int、unsigned int、long 或 unsigned long,具体取决于编译器给出的规则。现在涉及的类型之一是“无符号空头”。在 16 位系统上,short 和 int 都可以是 16 位,因此 unsigned short 不能“提升”为 int,而是 unsigned int。在 32 位系统上,int 将为 32 位,无符号短线将提升为 int。因此,可以使用无符号 int 或 int 操作数执行操作,这有所不同。特别是如果你比较数字。
打开所有可用的警告,希望您会被告知不良行为。
评论
unsigned long
评论
int
int
uint16, uint32
int
long int
lwTempC <= ignore_time
typedef unsigned long uint32 ; typedef unsigned short uint16 ; typedef unsigned char uint8 ;