一次C++调试记录

之前开发用Linux C比较多,C++中的STL 容器基本没有接触过。最近在学习C++,平时用到c++ 17中的部分新特性,下面就简单分享下自己C++的学习流程。

一、环境搭建

本人使用的是CentOS 7系统,该系统默认的g++版本不支持c++17的新特性。所以,首先需要做的就是升级新版本的g++。

  1. ftp://ftp.mirrorservice.org/sites/sourceware.org/pub/gcc/releases/网站上选择支持c++17的gcc版本,并使用wget下载到Linux系统中:wget ftp://ftp.mirrorservice.org/sites/sourceware.org/pub/gcc/releases/gcc-7.1.0/gcc-7.1.0.tar.bz2
  2. 安装编译gcc需要的依赖包 sudo yum install gmp-devel mpfr-devel libmpc-devel -y
  3. 解压gcc压缩包到temp文件夹  tar -jxf gcc-7.1.0.tar.bz2 -C temp
  4. 进入到temp/gcc目录下,执行 gcc ./configure --enable-checking=release --enable-languages=c,c++ --disable-multilib && make 进行gcc的编译(这个步骤耗时较长)
  5. 安装新版gcc  sudo make install
  6. 由于在./configure阶段未指定安装路径,那么新版的gcc的默认安装位置就是/usr/local/目录下,修改标准库的软连接使其指向新版本的标准库 sudo ln -sf /usr/local/lib64/libstdc++.so.6.0.23 /lib64/libstdc++.so.6
  7. 需要使用c++17的特性时,需要在Makefile的CXXFLAGS变量中添加 -std=c++17 

 

     gdb默认情况下是不支持c++容器输出的,不过在gdb 7.0版本之后,可以通过添加插件的方式来支持c++容器输出

  1. 检查gdb版本 gdb --version, (如果版本号低于7.0就不用往下看了)
  2. 在当前用户的home目录中(如/home/sxhlinux)下载 插件代码 svn co svn://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/python (没有svn的,需要通过 sudo yum install svn -y 安装)然后执行mv python .gdb_stl 将该文件夹重命名(使其隐藏)
  3. 执行 vim ~/.gdbinit,编辑gdb配置文件,添加如下内容

    add-auto-load-safe-path /usr/local/lib64/libstdc++.so.6.0.23-gdb.py  #文件的版本号,根据这个目录中的实际文件版本号确定
    
    python
    import sys
    sys.path.append("/usr/local/share/gcc-7.1.0/python")
    sys.path.insert(0, ‘/home/sxhlinux/.gdb_stl‘)     #注:将第二个参数中的路径改成自己的.gdb_stl文件夹路径
    from libstdcxx.v6.printers import register_libstdcxx_printers
    register_libstdcxx_printers (None)
    end
    

二、gdb 调试示例

  1. 下面的代码是将带有数字特征的分词(用unorder_map保存),按照一定的规则(分词的数字特征)进行合并

    #include <iostream>
    #include <cstdlib>
    #include <map>
    #include <unordered_map>
    
    using namespace std;
    
    template <typename T1, typename T2>
    bool merge_tokens(T1 &target, const T2 &rules)
    {
        auto pre = target.begin();
        for (auto token = target.begin(); token != target.end(); ) {
            if (pre == token) {
                token ++;
                continue;
            }
    
            auto range = rules.equal_range(pre->second);
            auto it = range.first;
            for (; it != range.second; it++) {
                if (it->second == token->second) {
                    break;
                }
            }
    
            if (it == range.second) {
                pre = token;
                token ++;
            }
            else {
                pre->first += token->first;
    //          target.insert(std::make_pair<typename T1::key_type, typename T1::mapped_type>(pre->first + token->first, 16));
                pre->second = 16;
                token = target.erase(token);
                pre = token;
            }
        }
    }
    
    int main ( int argc, char *argv[] )
    {
        unordered_map<string, size_t> tokens = {{"def", 22}, {"ghi", 100}, {"abc", 22}};
        unordered_multimap<size_t, size_t> rules = {{22, 100}, {100, 22}, {1, 38}};
        merge_tokens(tokens, rules);
    
        return EXIT_SUCCESS;
    }               /* ----------  end of function main  ---------- */
    
  1. 编译该文件,提示 31行

    test.cpp:31:15: error: passing ‘const std::__cxx11::basic_string<char>’ as ‘this’ argument discards qualifiers [-fpermissive]
    pre->first += token->first;
    ~~~~~~~~~~~^~~~~~~~~~~~~~
    
    /usr/local/include/c++/7.1.0/bits/basic_string.h:1122:7: note:   in call to ‘std::__cxx11::basic_string<_CharT, _Traits, _Alloc>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator+=(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’
           operator+=(const basic_string& __str)
           ^~~~~~~~
    

根据错误提示:string 的运算符 += 要求参数是一个 const string类型(作为右值,非const类型也可以作为const类型的参数使用),返回值是一个string类型。再看 出错的语句 pre->first += token->first; 根据mian函数中的tokens的定义,token和pre的first成员都应该是string而不是const string。

  1. 将报错的这一行注释掉,然后用gdb查看下pre->first和token->first的具体类型。具体如下

    (gdb) whatis target
    type = std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, unsigned long> &
    (gdb) whatis target.begin()
    type = std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, unsigned long, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, unsigned long> > >::iterator
    (gdb) whatis pre
    type = std::__detail::_Node_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, unsigned long>, false, true>
    

根据上面显示的,target两个参数类型确实和定义的一样,string和unsigned long;target.begin()类型说明中的std::allocator的模板参数pair的第一个参数为 string const,说明在创建unordered_map时,key的类型为const string而不是string(猜测这跟map与key相关的只有增加、删除而没有修改操作有关)。因为allocator在申请空间时,已经隐式的将string转成了const string,所以,pre->first的类型是const string而不是string(也就无法进行+=,=等相关操作)。

  1. 根据第三步的分析结果,要实现合并元素的效果,只能是将合并后的值作为一个新的pair插入到原来的map中,然后将原来的两个pair删除。代码如下:

                target.insert(std::make_pair<typename T1::key_type, typename T1::mapped_type>(pre->first + token->first, 16));
                target.erase(pre);
                token = target.erase(token);
                pre = token;
    

三、总结

很多时候我们遇到问题首先想到的是将错误复制下来,然后粘贴到google搜索框中,漫无目的的去寻找答案,而不是仔细分析查看gcc给出的错误提示。跟我的经验,很多时候gcc给出的提示相当明显,认真仔细阅读大部分可以很快找出解决方案,剩余的一部分棘手问题可以借助搜索引擎(PS:当搜索英文提示时,如果没有google,可以使用英文版的必应,效果也不错)

时间: 2024-10-12 23:08:46

一次C++调试记录的相关文章

Android KitKat 4.4 Wifi移植之AP模式与网络共享功能调试记录

Tethering技术在移动平台上已经运用的越来越广泛了,它可以把移动设备当做一个接入点,其它的设备可以通过Wi-Fi,USB或是Bluetooth等方式连接到此移动设备.在Android中可以将Wifi设为AP模式作为WLAN接入点,从而与其他设备共享Android的互联网连接.Android成为接入点后,就无法通过WLAN连接使用Android的应用程序访问互联网,但可以通过其他方式如以太网或移动网络访问互联网.此时以太网或移动网络在网络共享(Tethering)中是作为upstream的角

ORACLE 11G 触发器调试记录Error: PLS-00201: identifier&#39;SYS.DBMS_SYSTEM&#39; must be declared

1,触发器内容如下 CREATE OR REPLACE TRIGGER"LOGON_DENIED_TO_ALERT" AFTER servererror ON DATABASE DECLARE message   VARCHAR2(168); ip        VARCHAR2(15); v_os_user VARCHAR2(80); v_module  VARCHAR2(50); v_action  VARCHAR2(50); v_pid     VARCHAR2(10); v_s

【原】各种语言疑难BUG调试记录

之前遇到棘手的BUG总是在处理过后就不管了,导致后面碰到后重复工作太多.现专门开辟一篇日志以记录接下来一路上的DEBUG记录. [C++] 1.mt.exe : general error c101008d: Failed to write the updated manifest to the resource of file 说明:由于VC需要把生成的文件中嵌入MANIFEST文件,而由于杀毒软件之类的会握有这个文件句柄(因为杀毒软件发现这个EXE,DLL正在读写),于是VC就写不进去了,方

上海机房阵列柜调试记录

1.vmare部分 vmotion http://qingping.blog.51cto.com/335806/404718/ storage vmotion http://qingping.blog.51cto.com/335806/396488 一些基本概念. vCenter的基本单位是DataCenter数据中心,一般以机房位置来划分,是vCenter的最高级的划分单位. Cluster:集群,多台ESXi服务器组成一个集群,可以提供高级功能,通常同一机房计算机会放入一个DataCente

stm32调试记录一

..\..\SYSTEM\usart\usart.c(1): error:  #5: cannot open source input file "sys.h": No such file or directory #include "..\sys\sys.h"这样就可以找到路径了 再次编译出现了问题 ..\..\SYSTEM\usart\..\sys\sys.h(3): error:  #5: cannot open source input file "

Video Test Pattern Generator(7.0)软件调试记录

Video Test Pattern Generator(7.0)软件调试记录 1 1. 2 XVidC_VideoMode 3 XVIDC_VM_576_50_I = XVIDC_VM_720x576_50_I 4 5 2. 6 typedef struct { 7 u16 HActive; 8 u16 HFrontPorch; 9 u16 HSyncWidth; 10 u16 HBackPorch; 11 u16 HTotal; 12 u8 HSyncPolarity; 13 u16 VAc

mysql 存储过程错误调试记录

 mysql存储过程错误调试记录 公司平台在mysql数据库上运行,一些存储过程报错,调试过程痛苦,记录错误及解决办法,供参考. 调试环境:dbForge Studio for MySQL 6.1版本,试用版: 1.BIZ_GET_ORGAN_BY_CONDITION 问题1:提示递归调用错误,递归次数太多:根据业务设置,最大255: [email protected]@max_sp_recursion_depth = 10; 常见如乱码造成导致条件失效,出现死循环: 问题2:变量的内容是乱

IOS真机调试记录

首先,登录到http://developer.apple.com/devcenter/ios/index.action,如果已经购买了iPhone Develop Program(iDP),登录进去后,页面右上角会看到如下图所示的页面: 点击第一项:iOS Provisioning Portal,然后会看到下面的页面: 点击进入Certificates,然后看到如下所示的页面: 点击图中的click here to download now,这会下载下来一个AppleWWDRCA.cer文件,这

Qualnet 调试记录

在Qualnet里添加了一个应用层协议,编译完全通过,但在运行时总是在63s内存读取错误.可以肯定是路由表更新处指针调用错误了.为了定位错误,最可靠的办法就是使用VS进行调试.但按照官方手册设置调试时,却出现了如下错误信息: 'qualnet.exe': Loaded 'C:\snt\qualnet\5.0\bin\qualnet.exe', Symbols loaded. 'qualnet.exe': Loaded 'C:\WINDOWS\system32\ntdll.dll' 'qualne

基于freescale i.Mx6(ARM)的阿里云oss调试记录

SS调试记录 1.1 开通oss服务 具体参考以下链接: https://help.aliyun.com/document_detail/31884.html?spm=a2c4g.11186623.6.558.n2g1UA 1.2 SDK安装 在ubuntu下安装,安装步骤如下: 安装CMake 执行以下命令安装CMake. sudo apt-get install cmake 安装第三方库 执行以下命令安装第三方库. sudo apt-get install libcurl4-openssl-