代码之家  ›  专栏  ›  技术社区  ›  Nik

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

  •  3
  • Nik  · 技术社区  · 7 年前

    一点背景 :我正在从 C C# 通过使用 C++/CLI 我注意到调试器显示方式的一个特点 floats doubles ,这取决于代码在哪个dll中执行(请参阅下面的代码和图像)。起初我认为这与管理/非管理差异有关,但后来我意识到如果我完全离开 C# 层之外,只使用非托管数据类型,同样的行为也表现出来。

    测试用例 :为了进一步探讨这个问题,我创建了一个单独的测试用例来清楚地识别奇怪的行为。我假设任何可能测试此代码的人都已经有了一个有效的解决方案 dllimport / dllexport / macros 设置我的名字叫 DLL_EXPORT . 如果你需要一个最小的工作头文件,请告诉我。这里的主要应用程序位于 C 以及从 dll。我正在使用 Visual Studio 2015 两个组件都是 32 bit .

    问题: 谁能解释观察到的行为,或者至少为我指出正确的方向?

    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标头

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

    //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;
    }
    

    C中的调试器 -的最后一行上的断点 floatTest()

    enter image description here

    C++/CLI中的调试器 -从第二行到最后一行的断点 floatTestCPP()

    enter image description here

    1 回复  |  直到 7 年前
        1
  •  1
  •   chux    7 年前

    考虑 本身不一定用C、C#或C++编码。

    "R" format :可以往返到相同数字的字符串。我怀疑这是一个 g

    如果没有MS源代码,以下只是一个很好的假设:

    调试输出足以区分 double 从附近的其他地方 双重的 . 所以代码不需要打印 "42.420000000000002" 但是 "42.42" 足够-无论使用何种格式。

    42.42作为IEEE 双重的 42.4200000000000017053025658242404460906982... 调试器当然不需要打印精确的值。

    潜在的类似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));
    }
    

    输出

    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
    

    双重的 以足够的文本精度返回到文本,并返回到 双重的 要“往返”数字,请参阅 Printf width specifier to maintain precision of floating-point value