Sup*_*pAl 31 c c++ embedded iar
我有一个简单的函数测试,如果两个数组彼此相反。它们似乎是相同的,只是tmp变量不同。一个有效,另一个无效。我一辈子都无法弄清楚为什么编译器会对此进行优化-如果确实存在优化问题(我的编译器是IAR Workbench v4.30.1)。这是我的代码:
// this works as expected
uint8 verifyInverseBuffer(uint8 *buf, uint8 *bufi, uint32 len)
{
uint8 tmp;
for (uint32 i = 0; i < len; i++)
{
tmp = ~bufi[i];
if (buf[i] != tmp)
{
return 0;
}
}
return 1;
}
// this does NOT work as expected (I only removed the tmp!)
uint8 verifyInverseBuffer(uint8 *buf, uint8 *bufi, uint32 len)
{
for (uint32 i = 0; i < len; i++)
{
if (buf[i] != (~bufi[i]))
{
return 0;
}
}
return 1;
}
Run Code Online (Sandbox Code Playgroud)
该代码的第一个版本有效,而第二个则无效。谁能找出原因?还是附带一些测试来探查出什么问题?
dbu*_*ush 43
您看到的是整数促销规则的结果。每当int在表达式中使用小于的变量时,值都会升为type int。
假设bufi[i]包含值255。其十六进制表示为0xFF。然后,此值是运算~符的操作数。因此,该值将首先被提升到int其中(假定它是32位)将有值0x000000FF,并应用~到这个给你0xFFFFFF00。然后,您可以将该值与buf[i]类型为的值进行比较uint8_t。该值0xFFFFFF00超出此范围,因此比较将始终为false。
如果将~back 的结果分配给type变量uint8_t,则该值0xFFFFFF00将转换为0x00。然后将此转换后的值与进行比较buf[i]。
因此,您看到的行为不是优化的结果,而是语言的规则。照常使用临时变量是解决此问题的一种方法。您还可以将结果转换为uint8:
if(buf[i] != (uint8)(~bufi[i]))
Run Code Online (Sandbox Code Playgroud)
或屏蔽掉最低位字节以外的所有字节:
if(buf[i] != (~bufi[i] & 0xff))
Run Code Online (Sandbox Code Playgroud)
Lun*_*din 22
问题是整数提升。该~操作是非常危险的!
如果为~bufi[i],则~根据整数提升来提升的操作数。使代码等同于~(int)bufi[i]。
因此,在第二种情况下,buf[i] != (~bufi[i])您得到类似的内容0xXX != 0xFFFFFFFFYY,其中“ XX”和“ YY”是您要比较的实际值,而0xFFFF是通过对a进行按位补码而放置的意外内容int。这将始终取值为,true以便编译器可以优化部分代码,从而创建一个非常细微的错误。
如果tmp = ~bufi[i];您通过截断0xFFFFFFFFYY为“ YY”(您感兴趣的值)来避开此错误。
有关详细信息,请参见隐式类型提升规则。还可以考虑采用MISRA-C来躲避此类细微的错误。
正如Lundin和dbush所指出的,第二个版本中的比较总是失败,因为uint8提升为的任何值的相反值int都不同于所有uint8值。换句话说,第二个版本等效于:
// this does NOT work as expected (I only removed the tmp!)
uint8 verifyInverseBuffer(uint8 *buf, uint8 *bufi, uint32 len) {
if (len) return 0;
return 1;
}
Run Code Online (Sandbox Code Playgroud)
可以看出在Godbolt的编译器的探险家,都gcc和clang彻底检测,并优化代码出来:
verifyInverseBuffer:
test edx, edx
sete al
ret
Run Code Online (Sandbox Code Playgroud)
gcc 产生一个相当隐晦的警告,指出可疑的有符号/无符号比较问题,这不是真正的问题...关闭但没有香蕉。
<source>: In function 'verifyInverseBuffer':
<source>:8:16: warning: comparison of promoted bitwise complement of an unsigned value with unsigned [-Wsign-compare]
8 | if (buf[i] != (~bufi[i]))
| ^~
Compiler returned: 0
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1180 次 |
| 最近记录: |