1. 程式人生 > >手把手教你除錯Linux C++ 程式碼

手把手教你除錯Linux C++ 程式碼

軟體除錯本身就是一項相對複雜的活動,他不僅要求除錯者有著清晰的思路,而且對除錯者本身的技能也有很高的要求。Windows下Visual Studio為我們做了很多的工作,使初學者基本上可以獲得一個所見即所得的除錯體驗,相對來說也比較容易上手。然而在linux平臺下,一切都顯得有些不同,倒不是說GDB有多難,只是對於習慣了visual studio的人來說剛開始會有些不適應。然而對於那些在windows 平臺下使用windbg除錯程式碼的人來說,情況會好很多,但是也要有個思維方式的轉變以及除錯命令的再適應過程。本文將帶你開啟GDB 除錯 Linux 下 C/C++的大門。

Agenda

1. 準備條件

2. GDB除錯單執行檔案

3. GDB除錯靜態連結庫

4. GDB除錯動態連結庫

1. 準備條件

由於Linux下沒有visual studio, 對於程式的編譯需要藉助makefile,下面我先晒出一個簡單的makefile,不求大而全,小巧可用就好。

#makefile
CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g
LDFLAGS=-g
LDLIBS=
AR=ar

SRCS=main.cc functions.cc
OBJS=$(subst .cc,.o,$(SRCS))

all: main
main: $(OBJS)
    $(CXX) $(LDFLAGS) -o main $(OBJS) -L. $(LDLIBS) 
    
main.o: main.cc functions.h testobj.h

functions.o: functions.h functions.cc

clean:
    $(RM) $(OBJS)

all-clean: clean
    $(RM) main

如下是相關的三個檔案直接copy就可以使用

main.cc/functions.cc/functions.h

#include<iostream>
#include"functions.h"
int main()
{
std::cout << "Enter two numbers:" << std::endl;
int v1 = 0, v2 = 0;
std::cin >> v1 >> v2;
std::cout << "The sum of " << v1 << " and " << v2
<< " is " << v1 + v2 << std::endl;

function();

return 0;
}

1 #include<iostream>
2 int function(void)
3 {
4     std::cout << "I am in a function!" << std::endl;
5     return 0;
6 }
1 int function(void);

將這4個檔案放入一個目錄下,到這個目錄下直接執行make就會產生一個可執行檔案main。

2. GDB除錯單執行檔案

除錯結果如下:
[email protected]:~/testmake/Test_L1$ gdb main
GNU gdb (Ubuntu 7.7-0ubuntu3) 7.7
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
Reading symbols from main...done.

(gdb) b 2 //在第二行設定斷點
Breakpoint 1 at 0x400a4a: file main.cc, line 2.
(gdb) r //全速執行
Starting program: /home/solidmango/testmake/Test_L1/main

Breakpoint 1, main () at main.cc:7
   std::cout << "Enter two numbers:" << std::endl;//斷點命中
(gdb) s
Enter two numbers:
   int v1 = 0, v2 = 0;
(gdb) s //單步執行
   std::cin >> v1 >> v2;
(gdb) n
6
   << " is " << v1 + v2 << std::endl;
(gdb) s
   std::cout << "The sum of " << v1 << " and " << v2
(gdb) s
   << " is " << v1 + v2 << std::endl;
(gdb) s
The sum of 5 and 6 is 11
   function();
(gdb)

3. GDB除錯靜態連結庫

對於靜態連結庫的除錯和單個的執行檔案相似,因為最終的檔案都被連結在一起。對於靜態連結庫的除錯需要兩個額外兩個輔助檔案以及對makefile和main.cc稍作修改,具體改動如下:

#makefile
CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g
LDFLAGS=-g
LDLIBS=-ltest #changed
AR=ar

SRCS=main.cc functions.cc
OBJS=$(subst .cc,.o,$(SRCS))

all: main
main: $(OBJS) libtest.a #changed
$(CXX) $(LDFLAGS) -o main $(OBJS) -L. $(LDLIBS) 
main.o: main.cc functions.h testobj.h 
functions.o: functions.h functions.cc 

clean: $(RM) $(OBJS) 

all-clean: clean $(RM) main
main.cc/testobj.cc/testobj.h
#include<iostream>
#include"functions.h"
#include"testobj.h"

int main()
{
std::cout << "Enter two numbers:" << std::endl;
int v1 = 0, v2 = 0;
std::cin >> v1 >> v2;
std::cout << "The sum of " << v1 << " and " << v2
<< " is " << v1 + v2 << std::endl;

function();

TestObj();

return 0;
}

#include<iostream>
int TestObj(void)
{
    std::cout << "I am in TestObj!" << std::endl;
    return 0;
}
int TestObj(void);

[email protected]:~/testmake/Test_L1$ g++ -g -c -o testobj.o testobj.cc
[email protected]lidmango-pc:~/testmake/Test_L1$ ar rv libtest.a testobj.o
ar: creating libtest.a
a - testobj.o
[email protected]:~/testmake/Test_L1$ make
g++  -g  -c -o main.o main.cc
g++  -g  -c -o functions.o functions.cc
g++ -g -o main main.o functions.o -L. -ltest 
[email protected]:~/testmake/Test_L1$ ./main
Enter two numbers:
6
The sum of 5 and 6 is 11
I am in a function!
I am in TestObj!
[email protected]:~/testmake/Test_L1$

4. GDB除錯動態連結庫對於動態連結庫的除錯和單個的執行檔案差別較大,相對於靜態連結庫的除錯只需要對makefile

稍作修改,具體改動如下:

生成相應的動態庫並copy到系統目錄

g++ -g -c -fPIC -o testobj.o testobj.cc
g++ -g  -shared -o libtest.so testobj.o
sudo cp libtest.so /lib/libtest.so

makefile

CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g
LDFLAGS=-g
LDLIBS=-ltest
AR=ar

SRCS=main.cc functions.cc
OBJS=$(subst .cc,.o,$(SRCS))

all: main
main: $(OBJS) libtest.so
    $(CXX) $(LDFLAGS) -o main $(OBJS) -L. $(LDLIBS) 
    
main.o: main.cc functions.h testobj.h

functions.o: functions.h functions.cc

clean:
    $(RM) $(OBJS)

all-clean: clean
    $(RM) main

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 除錯結果如下:<br>[email protected]:~/testmake/Test_L1$ gdb main GNU gdb (Ubuntu 7.7-0ubuntu3) 7.7 Copyright (C) 2014 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.  Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from main...done. (gdb) b TestObj Breakpoint 1 at 0x400910 (gdb) r Starting program: /home/solidmango/testmake/Test_L1/main Enter two numbers: 7 8 The sum of 7 and 8 is 15 I am in a function! Breakpoint 1, 0x0000000000400910 in TestObj()@plt () (gdb) s Single stepping until exit from function [email protected], which has no line number information. TestObj () at testobj.cc:3 3   { (gdb) bt #0  TestObj () at testobj.cc:3 #1  0x0000000000400b05 in main () at main.cc:17 (gdb) info sharedlibrary From                To                  Syms Read   Shared Object Library 0x00007ffff7ddaae0  0x00007ffff7df54e0  Yes         /lib64/ld-linux-x86-64.so.2 0x00007ffff7bd8850  0x00007ffff7bd89c5  Yes         /lib/libtest.so 0x00007ffff792f5c0  0x00007ffff799299a  Yes (*)     /usr/lib/x86_64-linux-gnu/libstdc++.so.6 0x00007ffff752d4a0  0x00007ffff7673413  Yes         /lib/x86_64-linux-gnu/libc.so.6 0x00007ffff720d610  0x00007ffff727c1b6  Yes         /lib/x86_64-linux-gnu/libm.so.6 0x00007ffff6ff4ab0  0x00007ffff7004995  Yes (*)     /lib/x86_64-linux-gnu/libgcc_s.so.1

相關推薦

手把手除錯Linux C++ 程式碼

軟體除錯本身就是一項相對複雜的活動,他不僅要求除錯者有著清晰的思路,而且對除錯者本身的技能也有很高的要求。Windows下Visual Studio為我們做了很多的工作,使初學者基本上可以獲得一個所見即所得的除錯體驗,相對來說也比較容易上手。然而在linux平臺下,一切都

Linux環境搭建 | 手把手安裝Linux虛擬機

界面 rup 對話 rtu 發行版 所在 兼容性 運維 編輯 前言 作為一名Linux工程師,不管是運維、應用、驅動方向,在工作中肯定會需要Linux環境。想要獲得Linux環境,一個辦法就是將電腦系統直接換成Linux系統,但我們平常用慣了Windows系統,直接切換為L

手把手Linux環境下安裝Python3

在上一篇文章《手把手教你啟用Win10的Linux子系統(超詳細)》我們已經學瞭如何在Win10環境下裝Linux子系統了,那麼這一篇文章我們將學習如何在該Linux系統下安裝Python3。 首先是按Win+R鍵調出cmd命令視窗,然後輸入輸入bash指令進

手把手做一個 C 語言編譯器(8):表示式

這是整個編譯器的最後一部分,解析表示式。什麼是表示式?表示式是將各種語言要素的一個組合,用來求值。例如:函式呼叫、變數賦值、運算子運算等等。 表示式的解析難點有二:一是運算子的優先順序問題,二是如何將表示式編譯成目的碼。我們就來逐一說明。 本系列: 運算子的優先順

手把手做一個 C 語言編譯器(7):語句

整個編譯器還剩下最後兩個部分:語句和表示式的解析。它們的內容比較多,主要涉及如何將語句和表示式編譯成彙編程式碼。這章講解語句的解析,相對於表示式來說它還是較為容易的。 本系列: 語句 C 語言區分“語句”(statement)和“表示式”(expression)兩

手把手做一個 C 語言編譯器(9):總結

恭喜你完成了自己的 C 語言編譯器,本章中我們發一發牢騷,說一說編寫編譯器值得注意的一些問題;編寫編譯器時遇到的一些難題。 本系列: 虛擬機器與目的碼 整個系列的一開始,我們就著手虛擬機器的實現。不知道你是否有同感,這部分對於整個編譯器的編寫其實是十分重要的。我認

手把手做一個 C 語言編譯器(2):虛擬機器

本章是“手把手教你構建 C 語言編譯器”系列的第三篇,本章我們要構建一臺虛擬的電腦,設計我們自己的指令集,執行我們的指令集,說得通俗一點就是自己實現一套匯編語言。它們將作為我們的編譯器最終輸出的目的碼。 本系列: 計算機的內部工作原理 我們關心計算機的三個基本部件

手把手做一個 C 語言編譯器(6):函式定義

由於語法分析本身比較複雜,所以我們將它拆分成 3 個部分進行講解,分別是:變數定義、函式定義、表示式。本章講解函式定義相關的內容。 本系列: EBNF 表示 這是上一章的 EBNF 方法中與函式定義相關的內容。 C

手把手做一個 C 語言編譯器(4):遞迴下降

本章我們將講解遞迴下降的方法,並用它完成一個基本的四則運算的語法分析器。 本系列: 什麼是遞迴下降 傳統上,編寫語法分析器有兩種方法,一種是自頂向下,一種是自底自上。自頂向下是從起始非終結符開始,不斷地對非終結符進行分解,直到匹配輸入的終結符;自底向上是不斷地將終

手把手做一個 C 語言編譯器(3):詞法分析器

本章我們要講解如何構建詞法分析器。 本系列: 什麼是詞法分析器 簡而言之,詞法分析器用於對原始碼字串做預處理,以減少語法分析器的複雜程度。 詞法分析器以原始碼字串為輸入,輸出為標記流(token stream),即一連串的標記,每個標記通常包括: (token,

手把手做一個 C 語言編譯器(0):前言

“手把手教你構建 C 語言編譯器” 這一系列教程將帶你從頭編寫一個 C 語言的編譯器。希望通過這個系列,我們能對編譯器的構建有一定的瞭解,同時,我們也將構建出一個能用的 C 語言編譯器,儘管有許多語法並不支援。 在開始進入正題之前,本篇是一些閒聊,談談這個系列的初衷

手把手做一個 C 語言編譯器(1):設計

本章是“手把手教你構建 C 語言編譯器”系列的第二篇,我們要從整體上講解如何設計我們的 C 語言編譯器。 本系列: 首先要說明的是,雖然標題是編譯器,但實際上我們構建的是 C 語言的直譯器,這意味著我們可以像執行指令碼一樣去執行 C 語言的原始碼檔案。這麼做的理由

手把手做一個 C 語言編譯器(5):變數定義

本章中我們用 EBNF 來大致描述我們實現的 C 語言的文法,並實現其中解析變數定義部分。 由於語法分析本身比較複雜,所以我們將它拆分成 3 個部分進行講解,分別是:變數定義、函式定義、表示式。 本系列: EBNF 表示 EBNF 是對前一章提到的 BNF 的擴充

手把手移植linux核心---------OK6410(一)

配置資訊: 移植核心:linux-3.3.5       可以從  http://www.kernel.org/     下載純正的版本    編譯環境:vmware下ubuntu11.04 交叉編譯版本:4.3.2 準備工作: 一塊OK6410開發板,交叉網線,串列埠線

手把手移植linux核心(目標平臺S3C2410)

Linux核心的最初版本由Linus Torvalds在1991年釋出,後來核心版本不斷更新: Linux1.0   1994年3月    僅支援386 Linux1.2   1995年3月    多

eclipse -- 手把手如何把java程式碼,打包成jar檔案以及轉換為exe可執行檔案

1、背景:     學習java時,教材中關於如題問題,只有一小節說明,而且要自己寫麻煩的配置檔案,最終結果卻只能轉換為jar檔案。實在是心有不爽。此篇部落格教你如何方便快捷地把java程式碼,打包成jar檔案以及轉換為exe可執行檔案 2、前言:     我們都知道Java可以將二進位制程式打包成可執

手把手安裝Linux(CentOS 7)系統及網路配置

準備工作 做U盤啟動 安裝系統 配置網路 檢視本地ip相關資訊

手把手Linux裝置驅動---定時器(一)(基於友善之臂4412開發板)

這個專題我們來說下Linux中的定時器。在Linux核心中,有這樣的一個定時器,叫做核心定時器,核心定時器用於控制某個函式,也就是定時器將要處理的函式在未來的某個特定的時間內執行。核心定時器註冊的處理函

手把手製作linux U盤啟動盤及安裝Ubuntu與win7雙系統

      linux系統簡介         與Windows系統相比,linux系統有很多優點,在開發中,linux也是一項必不可少的技能。基本後臺伺服器都部署在linux上。linux是基於Un

使用VS2017除錯Linux C++程式碼

VS2017版本現已支援開發Linux專案,就是在VS上面寫程式碼,而編譯和執行是在Linux環境下。 使用場景: 假如,程式碼最終是執行在Linux系統上,而我們又不想在Linux環境下寫程式碼,想借用VS強大的開發功能做開發,那麼就可以在VS上面建立