简体   繁体   English

C vs C ++(CLI)中调试器中的浮点表示

[英]Floating Point Representation in Debugger in C vs C++(CLI)

A little background : I was working on some data conversion from C to C# by using a C++/CLI midlayer, and I noticed a peculiarity with the way the debugger shows floats and doubles , depending on which dll the code is executing in (see code and images below). 一点背景 :我正在使用C++/CLI中间层进行从CC#的一些数据转换,我注意到调试器显示floatsdoubles的方式的特殊性,具体取决于代码执行的dll(参见代码)和图片如下)。 At first I thought it had something to do with managed/unmanaged differences, but then I realized that if I completely left the C# layer out of it and only used unmanaged data types, the same behaviour was exhibited. 起初我认为它与托管/非托管差异有关,但后来我意识到如果我完全离开C#层并且只使用非托管数据类型,则表现出相同的行为。

Test Case : To further explore the issue, I created an isolated test case to clearly identify the strange behaviour. 测试用例 :为了进一步探讨这个问题,我创建了一个独立的测试用例,以清楚地识别出奇怪的行为。 I am assuming that anyone who may be testing this code already has a working Solution and dllimport / dllexport / macros set up. 我假设任何可能正在测试此代码的人都已经设置了一个有效的解决方案和dllimport / dllexport / Mine is called DLL_EXPORT . 我叫做DLL_EXPORT If you need a minimal working header file, let me know. 如果您需要最小的工作头文件,请告诉我。 Here the main application is in C and calling a function from a C++/CLI dll. 这里的主要应用程序是C并从C++/CLI dll调用函数。 I am using Visual Studio 2015 and both assemblies are 32 bit . 我使用的是Visual Studio 2015 ,两个程序集都是32 bit

I am a bit concerned, as I am not sure if this is something I need to worry about or it's just something the debugger is doing (I am leaning towards the latter). 我有点担心,因为我不确定这是否是我需要担心的事情,或者它只是调试器正在做的事情(我倾向于后者)。 And to be quite honest, I am just outright curious as to what's happening here. 说实话,我对这里发生的事情完全好奇。

Question: Can anyone explain the observed behaviour or at least point me in the right direction? 问题:任何人都可以解释观察到的行为或者至少指出我正确的方向吗?

C - Calling Function C - 调用函数

void floatTest()
{
    float floatValC = 42.42f;
    double doubleValC = 42.42;
    //even if passing the address, behaviour is same as all others.
    float retFloat = 42.42f;
    double retDouble = 42.42;
    int sizeOfFloatC = sizeof(float);
    int sizeOfDoubleC = sizeof(double);

    floatTestCPP(floatValC, doubleValC, &retFloat, &retDouble);

    //do some dummy math to make compiler happy (i.e. no unsused variable warnings)
    sizeOfFloatC = sizeOfFloatC + sizeOfDoubleC;//break point here
}

C++/CLI Header C ++ / CLI标头

DLL_EXPORT void floatTestCPP(float floatVal, double doubleVal, 
      float *floatRet, double *doubleRet);

C++/CLI Source C ++ / CLI源代码

//as you can see, there are no managed types in this function
void floatTestCPP(float floatVal, double doubleVal, float *floatRet, double *doubleRet)
{
    float floatLocal = floatVal;
    double doubleLocal = doubleVal;

    int sizeOfFloatCPP = sizeof(float);
    int sizeOfDoubleCPP = sizeof(double);

    *floatRet = 42.42f;
    *doubleRet = 42.42;

    //do some dummy math to make compiler happy (no warnings)
    floatLocal = (float)doubleLocal;//break point here
    sizeOfDoubleCPP = sizeOfFloatCPP;
}

Debugger in C - break point on last line of floatTest() C中的调试器 - floatTest()最后一行的floatTest()

在此输入图像描述

Debugger in C++/CLI - break point on the second to last line of floatTestCPP() C ++ / CLI中的调试器 - floatTestCPP()倒数第二行的floatTestCPP()

在此输入图像描述

Consider Debugger in C++/CLI itself is not necessarily coded in C, C# or C++. 考虑C ++ / CLI中的调试器本身不一定用C,C#或C ++编码。

MS libraries support the "R" format : A string that can round-trip to an identical number. MS库支持“R”格式 :可以往返于相同数字的字符串。 I suspect this or a g format was used. 我怀疑使用了这种或g格式。

Without MS source code, the following is only a good supposition: 没有MS源代码,以下只是一个很好的假设:

The debug output is enough to distinguish the double from other nearby double . 调试输出足以区分double与其他附近的double So code need not print "42.420000000000002" , but "42.42" is sufficient - whatever format is used. 所以代码不需要打印"42.420000000000002" ,但"42.42"就足够了 - 无论使用什么格式。

42.42 as an IEEE double is about 42.4200000000000017053025658242404460906982... and the debugger certainly need not print the exact value. 作为IEEE double 42.42约为42.4200000000000017053025658242404460906982...并且调试器当然不需要打印确切的值。

Potential; 潜在; similar C code 类似的C代码

int main(void) {
  puts("12.34567890123456");
  double d = 42.42;
  printf("%.16g\n", nextafter(d,0));
  printf("%.16g\n", d);
  printf("%.17g\n", d);
  printf("%.16g\n", nextafter(d,2*d));
  d = 1 / 3.0f;
  printf("%.9g\n", nextafterf(d,0));
  printf("%.9g\n", d);
  printf("%.9g\n", nextafterf(d,2*d));
  d = 1 / 3.0f;
  printf("%.16g\n", nextafter(d,0));
  printf("%.16g\n", d);
  printf("%.16g\n", nextafter(d,2*d));
}

output 产量

12.34567890123456
42.41999999999999
42.42
42.420000000000002   // this level of precision not needed.
42.42000000000001
0.333333313
0.333333343
0.333333373
0.3333333432674407
0.3333333432674408
0.3333333432674409

For your code to convert a double to text with sufficient textual precision and back to double to "round-trip" the number, see Printf width specifier to maintain precision of floating-point value . 对于您的代码,将double转换为具有足够文本精度的文本并返回double以“往返”该数字,请参阅Printf宽度说明符以保持浮点值的精度

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM