gxqcn 发表于 2020-3-17 14:42:28

发现微软编译器三路比较运算(<=>)的一个大 bug!

有符号的大整数加减法,最终都会进行无符号的加减法。
而无符号的减法,必须得是较大者作为被减数,也就是说得先有个比较运算。

而就是这一步,曾害得我花了好几个小时去排查一个 bug,最终居然是微软编译器的问题!
// test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"

#include <compare>
#include <iostream>

// 2020-03-16, gxqcn 发现编译器 bug: 如写成 const auto cmp{ *--pl <=> *--pr }, 当 0 != cmp 时,指针会多移动一次!
int main()
{
    const auto test{ []( auto a, auto b )
    {
      std::cout << "before compare: a=" << a << " b=" << b << "\n";
      const auto cmp{ a++ <=> b++ };
      std::cout << "aftercompare: a=" << a << " b=" << b << "\n\n";

      // 为了对比检测 std::max() 是否有类似表现,
      std::cout << "std::max( a++, b++ ) = " << std::max( a++, b++ ) << "\n";
      std::cout << "afterstd::max: a=" << a << " b=" << b << "\n\n";
    }};

    test( 1, 1 );   // 测试表明:当相等时,表现与预期相符
    test( 1, 2 );   // 测试表明:当不等时,表现与预期不符

    std::cout << "-------------------------\n\n";

    int v1[]{ 1, 2, 3, 4, 5, 6 };
    int v2[]{ 1, 2, 0, 9, 0, 6 };

    auto p1{ std::cbegin( v1 ) - 1 };
    auto p2{ std::cbegin( v2 ) - 1 };

    std::cout << "compare: v1{ 1, 2, 3, 4, 5, 6 } <=> v2{ 1, 2, 0, 9, 0, 6 }\n\n";

    for ( auto index{ 0 }; sizeof( v1 ) / sizeof( v1[ 0 ] ) != index; ++index )
    {
      if ( const auto cmp{ *++p1 <=> *++p2 }; 0 != cmp )
      {
            std::cout << "v1[" << index << "] = " << v1[ index ] << "; *p1 =" << *p1 << "\n";
            std::cout << "v2[" << index << "] = " << v2[ index ] << "; *p2 =" << *p2 << "\n";

            if ( 0 < cmp )
            {
                std::cout << "\nv1 > v2";
            }
            else
            {
                std::cout << "\nv1 < v2";
            }

            if (( v1[ index ] <=> v2[ index ] ) == cmp )
            {
                std::cout << ", it's right.\n\n";
            }
            else
            {
                std::cout << " ?! it's wrong!!\n\n";
            }

            break;
      }
    }

    system( "pause" );
}
注意:需在 属性页->常规->C++语言标准 中设定“预览 - 最新 C++ 工作草案中的功能 (std:c++latest)”才能编译

其运行结果如下:
before compare: a=1 b=1
aftercompare: a=2 b=2

std::max( a++, b++ ) = 2
afterstd::max: a=3 b=3

before compare: a=1 b=2
aftercompare: a=3 b=4

std::max( a++, b++ ) = 4
afterstd::max: a=4 b=5

-------------------------

compare: v1{ 1, 2, 3, 4, 5, 6 } <=> v2{ 1, 2, 0, 9, 0, 6 }

v1 = 3; *p1 =4
v2 = 0; *p2 =9

v1 < v2 ?! it's wrong!!

请按任意键继续. . .
这个 bug 不仅是运算结果不对的问题,还有导致指针越界的风险,
解决的方式是:在 <=> 两端,尽量避免自增/自减等运算,
不过这只是避坑而已,坑仍在那里!

这个 bug 是昨天上午发现的,当时版本是 VS2019 16.4.6;
今早微软对它进行了更新,版本为 16.5.0;
但刚才测试了下,该 bug 依然存在。

mathematica 发表于 2020-3-17 15:46:52

软件能不升级就不升级,能干活第一,新版本的软件,基本就是拿别人当小白鼠,
软件追求稳定能干活第一!

gxqcn 发表于 2020-3-17 15:52:59

你不是开发者,不要来掺乎;拿别人做小白鼠,看是源于态度还是做事严谨性,至少微软不是,我也不是。
我发这个帖子,只是为了提醒其他人的。

mathematica 发表于 2020-3-17 16:16:01

gxqcn 发表于 2020-3-17 15:52
你不是开发者,不要来掺乎;拿别人做小白鼠,看是源于态度还是做事严谨性,至少微软不是,我也不是。
我发 ...

虽然我不是开发者,但是我也经常码代码呀!
新版本的软件就是拿别人当小白鼠,微软出新操作系统都是
先发个版本出来,拿别人当小白鼠的,
活的时间长了,我现在变保守了,用的程序软件,
能不升级就不升级,程序软件,能稳定地干活,才是第一选择!
新功能永远最多只能排第二位!

mathematica 发表于 2020-3-17 16:21:39

gxqcn 发表于 2020-3-17 15:52
你不是开发者,不要来掺乎;拿别人做小白鼠,看是源于态度还是做事严谨性,至少微软不是,我也不是。
我发 ...

mathematica倒是真的有bug,
https://bbs.emath.ac.cn/forum.php?mod=redirect&goto=findpost&ptid=15286&pid=76977&fromuid=865

liangbch 发表于 2020-3-18 09:27:10

几乎所有人都同意,c++是最复杂的语言.c++20相对于c++98,几乎就是一门新语言.因为其复杂,学习成本太大,大量C++项目是基于旧的标准编写的,特别是一些历史项目.另外,因为其复杂,图书的更新也比较慢.目前,别说是c++17,c++19方面的书了,就是将c++11的图书也没几本.语言的标准,不建议使用最新的.对于最新的标准,编译器支持的一般比较有限,换个编译器,可能就出问题.目前,我公司推荐用C++11标准.太新的标准,学习起来真的吃不消.

gxqcn 发表于 2020-3-18 09:52:49

我觉得 C++ 标准进化最大的版本是 C++11,当然其经历的时间跨度也最大,之后的只是增补一些标准,使之更方便。
由于近几年标准更新得比较快,图书相对会跟不上;但可通过阅读相关的技术标准网站,还是能迅速跟上的。

以前要重载比较运算符有六种(<,<=,>,>=,==,!=);用新标准后,仅需重载两个即可:(<=>, == )
一般来说,用新的标准写代码,代码可以更优雅更自然更易读,可提效防低级失误,这何尝不是一种生产力?
当然,对于新生事物,也要保持一点警惕之心,需多加测试。

mathematica 发表于 2020-3-18 12:41:04

gxqcn 发表于 2020-3-18 09:52
我觉得 C++ 标准进化最大的版本是 C++11,当然其经历的时间跨度也最大,之后的只是增补一些标准,使之更方 ...

我的人生经验就是:能不升级就不升级!
就像地球的地转轴的角度发生了改变的话,地球的气候又将发生变化,
人一旦习惯了过去的版本,再去习惯新版本很啰嗦,
我以前不明白老同志用的CAD为什么那么落后,
后来阅历增加,渐渐明白了,适应新的版本需要一个过程,
还可能面临着种种插件不兼容的问题,而人已经习惯了旧版本,
所以能稳定地干活才是硬道理!

mathematica 发表于 2020-3-18 12:46:08

像vim这种软件,升级后,有时候特性就变化了,
配置文件都改变了

mathematica 发表于 2020-3-18 12:48:06

我现在写脚本,都注明是什么操作系统,64位还是32位,运行的软件是什么版本,等等,
就怕升级后找不到原来的版本。
页: [1] 2 3 4
查看完整版本: 发现微软编译器三路比较运算(<=>)的一个大 bug!