Visual Studio调试与发布版本:比较int和float不匹配
Visual Studio debug vs. release build: comparing int and float missmatch
看看这个例子:
#include <stdio.h>
int main() {
int i= 16777217;
float f = 16777216.0;
float g = i;
if( i == f )
printf("eqn");
else
printf("neqn");
if( g == f )
printf("eqn");
else
printf("neqn");
return 0;
}
在发布模式下使用Visual Studio 2010 C++(VS),gcc或g++(4.9.2),具有输出
eq
eq
这对我来说是合理的:在第一次比较期间,i
被隐式地转换为浮点,其中尾数中的有效位被截断。因此,i
和f
都具有与相等性相比相同的比特模式。在第二个if
中,应用相同的转换,但是在定义和初始化g
时已经执行了转换。
然而,在调试模式下使用VS,结果是
neq
eq
似乎没有应用第一个if
中比较期间的隐式转换(作为C和C++中常见算术转换的一部分)。这是真的吗?有没有VS机制可以防止在比较浮点和int时出现这种误报(更精确地转换为int/foat)?根据MSDN VS C++遵循的标准。
我已经用这个函数检查了比特表示。对于所有编译器,它都会屈服于
i = 00000001000000000000000000000001
f = 01001011100000000000000000000000
g = 01001011100000000000000000000000
VS上的float.h
状态为#define FLT_MANT_DIG 24
,因此所描述的截断问题也应该成立。
我在同一台机器(英特尔i5-3570K)上编译了所有内容,但在虚拟盒子中为VS编译。在另一台机器上使用VS编译也会打印neq/eq
。
EDIT:汇编程序代码附加
差异_debug.am
; Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01
TITLE c:Usersuserdocumentsvisual studio 2010Projectsdifferencesdifferencesdifferences.cpp
.686P
.XMM
include listing.inc
.model flat
INCLUDELIB MSVCRTD
INCLUDELIB OLDNAMES
PUBLIC ??_C@_04LMPLCMBC@neq?6?$AA@ ; `string'
PUBLIC ??_C@_03HNJPMNDP@eq?6?$AA@ ; `string'
PUBLIC __real@4b800000
PUBLIC _wmain
EXTRN __imp__printf:PROC
EXTRN __fltused:DWORD
EXTRN __RTC_CheckEsp:PROC
EXTRN __RTC_Shutdown:PROC
EXTRN __RTC_InitBase:PROC
; COMDAT ??_C@_04LMPLCMBC@neq?6?$AA@
; File c:usersuserdocumentsvisual studio 2010projectsdifferencesdifferencesdifferences.cpp
CONST SEGMENT
??_C@_04LMPLCMBC@neq?6?$AA@ DB 'neq', 0aH, 00H ; `string'
CONST ENDS
; COMDAT ??_C@_03HNJPMNDP@eq?6?$AA@
CONST SEGMENT
??_C@_03HNJPMNDP@eq?6?$AA@ DB 'eq', 0aH, 00H ; `string'
CONST ENDS
; COMDAT __real@4b800000
CONST SEGMENT
__real@4b800000 DD 04b800000r ; 1.67772e+007
CONST ENDS
; COMDAT rtc$TMZ
rtc$TMZ SEGMENT
__RTC_Shutdown.rtc$TMZ DD FLAT:__RTC_Shutdown
rtc$TMZ ENDS
; COMDAT rtc$IMZ
rtc$IMZ SEGMENT
__RTC_InitBase.rtc$IMZ DD FLAT:__RTC_InitBase
; Function compile flags: /Odtp /RTCsu /ZI
rtc$IMZ ENDS
; COMDAT _wmain
_TEXT SEGMENT
_g$ = -32 ; size = 4
_f$ = -20 ; size = 4
_i$ = -8 ; size = 4
_argc$ = 8 ; size = 4
_argv$ = 12 ; size = 4
_wmain PROC ; COMDAT
; Line 7
push ebp
mov ebp, esp
sub esp, 228 ; 000000e4H
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-228]
mov ecx, 57 ; 00000039H
mov eax, -858993460 ; ccccccccH
rep stosd
; Line 8
mov DWORD PTR _i$[ebp], 16777217 ; 01000001H
; Line 9
fld DWORD PTR __real@4b800000
fstp DWORD PTR _f$[ebp]
; Line 10
fild DWORD PTR _i$[ebp]
fstp DWORD PTR _g$[ebp]
; Line 13
fild DWORD PTR _i$[ebp]
fld DWORD PTR _f$[ebp]
fucompp
fnstsw ax
test ah, 68 ; 00000044H
jp SHORT $LN4@wmain
; Line 14
mov esi, esp
push OFFSET ??_C@_03HNJPMNDP@eq?6?$AA@
call DWORD PTR __imp__printf
add esp, 4
cmp esi, esp
call __RTC_CheckEsp
; Line 15
jmp SHORT $LN3@wmain
$LN4@wmain:
; Line 16
mov esi, esp
push OFFSET ??_C@_04LMPLCMBC@neq?6?$AA@
call DWORD PTR __imp__printf
add esp, 4
cmp esi, esp
call __RTC_CheckEsp
$LN3@wmain:
; Line 19
fld DWORD PTR _g$[ebp]
fld DWORD PTR _f$[ebp]
fucompp
fnstsw ax
test ah, 68 ; 00000044H
jp SHORT $LN2@wmain
; Line 20
mov esi, esp
push OFFSET ??_C@_03HNJPMNDP@eq?6?$AA@
call DWORD PTR __imp__printf
add esp, 4
cmp esi, esp
call __RTC_CheckEsp
; Line 21
jmp SHORT $LN1@wmain
$LN2@wmain:
; Line 22
mov esi, esp
push OFFSET ??_C@_04LMPLCMBC@neq?6?$AA@
call DWORD PTR __imp__printf
add esp, 4
cmp esi, esp
call __RTC_CheckEsp
$LN1@wmain:
; Line 24
xor eax, eax
; Line 26
pop edi
pop esi
pop ebx
add esp, 228 ; 000000e4H
cmp ebp, esp
call __RTC_CheckEsp
mov esp, ebp
pop ebp
ret 0
_wmain ENDP
_TEXT ENDS
END
差异_租赁.am
; Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01
TITLE c:Usersuserdocumentsvisual studio 2010Projectsdifferencesdifferencesdifferences.cpp
.686P
.XMM
include listing.inc
.model flat
INCLUDELIB OLDNAMES
PUBLIC ??_C@_03HNJPMNDP@eq?6?$AA@ ; `string'
PUBLIC ??_C@_04LMPLCMBC@neq?6?$AA@ ; `string'
EXTRN @__security_check_cookie@4:PROC
EXTRN __imp__printf:PROC
; COMDAT ??_C@_04LMPLCMBC@neq?6?$AA@
CONST SEGMENT
??_C@_04LMPLCMBC@neq?6?$AA@ DB 'neq', 0aH, 00H ; `string'
CONST ENDS
; COMDAT ??_C@_03HNJPMNDP@eq?6?$AA@
CONST SEGMENT
??_C@_03HNJPMNDP@eq?6?$AA@ DB 'eq', 0aH, 00H ; `string'
CONST ENDS
PUBLIC _wmain
EXTRN __fltused:DWORD
; Function compile flags: /Ogtp
; COMDAT _wmain
_TEXT SEGMENT
_argc$ = 8 ; size = 4
_argv$ = 12 ; size = 4
_wmain PROC ; COMDAT
; File c:usersuserdocumentsvisual studio 2010projectsdifferencesdifferencesdifferences.cpp
; Line 7
push esi
; Line 14
mov esi, DWORD PTR __imp__printf
push OFFSET ??_C@_03HNJPMNDP@eq?6?$AA@
call esi
; Line 20
push OFFSET ??_C@_03HNJPMNDP@eq?6?$AA@
call esi
add esp, 8
; Line 24
xor eax, eax
pop esi
; Line 26
ret 0
_wmain ENDP
_TEXT ENDS
END
如果我们对版本ASM:进行解包
; Line 14
push OFFSET ??_C@_03HNJPMNDP@eq?6?$AA@
call DWORD PTR __imp__printf
add esp, 4
; Line 18
xor eax, eax
; Line 20
ret 0
它只是打印eq
并退出,这表明浮动比较刚刚完全优化。对于调试程序集,我们使用fld
和fild
指令看到它:
; Line 9
fld DWORD PTR __real@4b800000
fstp DWORD PTR _f$[ebp]
; Line 10
fild DWORD PTR _i$[ebp]
fstp DWORD PTR _g$[ebp]
; Line 13
fild DWORD PTR _i$[ebp]
这些是IA32
指令,它是Visual Studio 2010中使用的默认体系结构。我怀疑使用/arch:SSE2
会得到不同的结果。
Hans Passant的评论基本上证实了我刚才所说的。
两组输出都符合C行为。
在执行FP数学时,C允许FP计算以比操作数格式更高的精度级别进行。
如果代码执行i == f
作为double
数学运算,则结果为"neq"
如果代码将i == f
执行为float
数学,则结果为"eq"
。
int i= 16777217;
float f = 16777216.0;
if( i == f )
printf("eqn");
else
printf("neqn");
除了赋值和强制转换(去除所有额外的范围和精度)外,具有浮动操作数的运算符、经过常规算术转换的值和浮动常量产生的值将按照范围和精度可能大于C11§5.2.4.2.29 类型要求的格式进行评估
现代的C编译器提供了FLT_EVAL_METHOD
,它指示了所使用的内容。
有没有VS机制可以防止在比较浮点和int时出现这种误报(更精确地转换为int/foat)?
为了强制进行float
比较,代码可以使用
if((float) i == f )
为了强制进行double
比较,代码可以使用
if((double) i == f )
- 比较if语句中的数组值和int值
- 比较两个整数在C++中与未知 int 类型的相等性
- 与 string.size() 比较时 int 的符号性显示警告
- 错误:运算符 [] 不匹配。在比较列表中的 int 和 int 时<int>,
- 在 IF 语句中比较 int 时出现奇怪的行为
- std::<int>betterer() 比较器与 partial_copy_sort 的困难,在 Mac OSX 上"no matching function call.."
- 无符号int的比较始终是正确的(NPOS问题?)
- 有没有办法比较用 int 初始化的 char 类型的数组的 2 个元素
- 将 int 与 double 进行比较的预处理器"invalid integer constant expression"
- 为 map<int、pair<int、int 创建比较器>>
- 如何使用将 const int 的运算符用作 int* 优先级队列的比较器
- 比较int和double时出错
- 比较INT会产生奇怪的结果
- Visual Studio调试与发布版本:比较int和float不匹配
- 如何比较 int 和字符
- C++ 如何比较<int>从开始到最后一个元素的集合 -1
- 为什么我可以在C中赋值/比较int和char ?
- 比较int和unsigned引用时警告,但比较g++/msvc的const(无ref)时没有警告
- 比较 (int)double 和 (int)int 时出现异常
- 比较 (int)double 和 (int)int 时出现异常