本教程将为您提供有关如何使用GDB在Linux中调试程序的基本思想。 如您所知,Visual Studio不能在Linux上运行,因此您必须使用命令行上提供的某些工具。 如果您讨厌命令行工具,请克服它,因为您一定会在职业生涯中的某个时候使用它们。 Linux中的所有命令均区分大小写,因此大写字母与小写字母不同。 如果您需要有关命令类型的基本信息
shell提示符下的command --help ,其中command是任何Linux命令,您将获得帮助屏幕。 这是您在Linux中将要了解的基本命令列表: ls –用法:ls [OPTION] ... [FILE] ...列出有关FILE的信息(默认为当前目录)。
示例:ls -l * .c
man –用法:man [OPTION] ... [COMMAND] ...显示有关命令的手册页
clear –清除外壳屏幕。 grep –用法:grep [OPTION] ... PATTERN [FILE] ...在每个FILE或标准输入中搜索PATTERN。
示例:grep -i'hello world'menu.h main.c
apropos –用法:apropos关键字...在命令中搜索KEYWORD。 非常适合在不确定命令时查找命令。
注意:我不得不稍微改变makefile部分,以便可以发布,因此只要您看到GNU_COMPILER用适当的命令替换它即可。
创建一个项目在Linux中,您将使用某种Shell(CShell或Bash等)来创建项目。 对于大学校园中基于Windows的计算机,您可能会使用
腻子 。 如果您已经在使用Linux或Unix的其他变体,那么您将拥有自己喜欢的Telnet / SSH客户端。 启动PuTTY会话后,您将获得类似于以下内容的屏幕:您的讲师/管理员将为您提供登录信息。 登录后,使用
ls命令。 对于大多数大学帐户,最初只有一个目录,即public_html。 通常,以某种目录方案将文件排列在磁盘上是一个好习惯。 注 :在Linux的大写字母创建目录显著; 项目是不一样的项目 。创建一个名为
使用mkdir命令的项目如下所示:更改为
使用cd命令的项目目录。 再次使用mkdir命令为此应用程序创建目录,并将其命名为MyProjectName1 ,其中MyProjectName1是您正在使用的程序的某种描述性名称。 例如,如果您要编写一个程序来计算MyTaxProgram中的所得税类型或类似的内容。现在,使用以前使用的相同cd命令更改到该目录。 此时,您的屏幕应如下所示:
现在我们有了项目目录,一旦我们创建了一些源文件,就需要创建一个makefile来处理项目的构建。 Makefile只是一个文本文件,与其他文件一样,但是其中包含一些特殊命令来构建可执行文件。 要创建文本文件,请执行以下操作:
1.首先,您是最喜欢的Unix编辑器,有几种,vi和emacs是使用最广泛的编辑器,但是pico / nano是大学实验室中大多数机器上都可以使用的优秀基本编辑器。 以下所有示例均使用pico,因此如果使用其他编辑器,则命令将有所不同。 类型
在命令提示符处显示pico ,您将看到以下屏幕:2.按ctrl-O并将文件另存为
makefile 。3.然后将以下文本添加到生成文件中:
main.exe: Source1.cpp
GNU_COMPILER -Wall Source1.cpp -o main.exe
注意 :名称Source1.cpp必须与下一节中将用于源代码文件的名称匹配。
4.再次按ctrl-O将更改保存到您的Makefile中。
创建一个新的源代码文件如果您正在使用新程序,则必须在创建项目目录后创建新的源代码文件。 以下步骤描述了如何创建新的源代码文件:
1.开始您最喜欢的Unix编辑器。
2.按ctrl-O并将文件另存为
Source1.cpp ,其中Source1.cpp是您正在使用的程序的某种描述性名称。 例如,如果您要编写一个程序来计算MyTaxProgram.cpp中的所得税类型或类似的内容。3.将以下文本添加到Source1.cpp文件中:
//
/// source1.cpp -
/// Purpose: Some source code file
///
/// Author: My Name
/// Date: January 1st, 2xxx
///
/// History
/// INI 2xxx-01-01 v1.00.00 Initial release
// Includes
#include <iostream>
#include <iomanip>
using namespace std;
int main(int argc, char** argv)
{
int ret_val = 0; // holds return value for main program
cout << "Hello World..." << endl;
return ret_val;
}
4.再次按ctrl-O将更改保存到Source1.cpp文件。
编译我的第一个程序
现在我们已经创建了makefile和Source1.cpp文件,所需要的就是运行make实用程序来创建我们的可执行文件以进行测试。
1.使用以下命令获取项目目录中当前文件的目录列表
ls命令。2.键入以下命令运行make命令
使在命令提示符下。3.来自编译器的消息(错误消息,警告消息和成功的编译/构建消息)将显示在屏幕上。
4.使用以下命令在我们的项目目录中获取当前文件的目录列表。
再次执行ls命令。 注意 :请注意由make创建的名为main.exe的新文件。 这是我们的可执行文件。 运行程序编译/构建成功后,在命令提示符下键入可执行文件的名称以运行它。 在这种情况下,我们的可执行文件是main.exe,因此在命令提示符下键入以下内容
./main.exe 。 应该显示以下输出:让我们在代码中添加以下文本,使该程序更有趣。
1.在main之前添加以下文本:
// Global constants and variables
#define PRG_NAME "MyProjectName1 - v 1.0.00"
#define CPY_RGHT "Copyright © 2xxx - "
#define AUTHOR "My Name"
// function prototypes
void show_copyright( void );
2.在main中的“ Hello World…”语句之前,将此调用添加到版权功能中:
show_copyright();
3.在main之后添加以下功能:
/
/// show_copyright
/// Purpose: Show program name and copyright notice
///
/// Parameters : None
/// Output : couts PRG_NAME, CPY_RGHT and AUTHOR defines
///
/// Returns : None
/// SideEffects : None
void show_copyright ( void )
{
cout << AUTHOR << "'s " << PRG_NAME << endl;
cout << CPY_RGHT << AUTHOR << endl << endl;
return;
}
完成所有这些更改后,您的Source1.cpp文件应如下所示:
4.现在像以前一样编译/构建并运行解决方案。 您应该看到以下屏幕:
调试程序有时可能很难确定为什么程序无法成功运行。 调试器允许程序员逐行浏览程序以查看其执行和失败。 在执行过程中也可以观察变量的值。 GNU C ++有一个调试器,可用于单步执行程序。 重要的是要注意程序必须首先编译。 让我们向Source1.cpp文件中添加更多代码(注意:此代码中有一个逻辑问题,可帮助您习惯调试):
1.在show_copyright函数原型之后的main之前添加以下代码:
char get_choice( void );
bool is_valid_choice( char );
2.在main中添加以下内容:
char choice;
3.将带有“ Hello World…”的提示语句更改为以下内容:
do{
cout << "Hello World..." << endl;
choice = get_choice();
}while(!is_valid_choice( choice));
4.在show_copyright函数之后添加以下函数:
/
/// get_choice
/// Purpose: Check to see if user wants to continue
///
/// Parameters: None
/// Output: Prompts user to continue program
///
/// Returns: char ch - Choice entered by user
/// SideEffects: None
/
char get_choice( void )
{
char ret_val;
char ch;
cout << "Do you want to continue (1 = Yes) (0 = No) ?: ";
cin >> ch;
ret_val = ch;
return ret_val;
}
/
/// is_valid_choice
/// Purpose: Checks for valid yes or no entry to continue
///
/// Parameters : char val - Current choice to continue
/// Output : Displays an error message if an invalid choice is passed
///
/// Returns : true if choice is valid and false otherwise
/// SideEffects : None
bool is_valid_choice( char val )
{
bool ret_val = true;
switch (val){
case 0:
case 1:
break;
default:
ret_val = false;
cout << "Invalid choice : " << val << endl;
cout << "Please enter one of the following(0 or 1) : " << endl;
break;
}
return ret_val;
}
5.和以前一样构建并运行该解决方案,您应该看到以下屏幕:
6.按
0 ,而不是像我们要求的那样停止程序,而是继续执行程序。 沃森在这里有一个错误。 按Ctrl + C停止执行程序。 现在,我们将使用GNU调试器命令gdb在代码中查找错误,但首先我们必须使用一些特殊的代码编译程序以启用调试。 为此,我们首先需要创建一个名为Debug的目录,然后修改我们的makefile以使用调试信息构建应用程序。 在命令提示符下,使用mkdir命令创建一个名为Debug的新目录。 使用ls命令确认目录已创建,并且您应该看到类似于以下内容的屏幕:接下来,在您选择的编辑器中打开makefile,我们将再次使用pico。 更改makefile,使其包含以下文本:
main.exe: Source1.cpp
GNU_COMPILER -Wall Source1.cpp -o main.exe
dbg_main: Source1.cpp
GNU_COMPILER -g –Wall Source1.cpp –o ./Debug/main.exe
现在,使用以下目标make dbg_main运行make并使用ls获取Debug目录的目录列表,并且屏幕上应该显示以下内容:
现在,我们将使用新编译的应用程序(其中包含调试信息)运行GNU调试器gdb。 类型
gdb Debug / main.exe在命令提示符下。 您应该看到类似于以下内容的屏幕:至此,您已进入调试器,可以从此处使用许多命令来帮助您弄清程序内部正在发生什么。 这是您将在GNU调试器中了解的基本命令列表:
帮助 –用法:帮助[命令]列出有关COMMAND的信息
示例:帮助运行或帮助断点
列表 –用法:列表[LINE或FUNCTION] [,] [LINE] ...列出文件中的行,一次列出10行
示例:清单1100
break –用法:break [LINE或FUNCTION]在指定的LINE或FUNCTION位置创建一个断点
示例:突破100
运行 –用法:运行[ARGUMENTS] ...使用指定的ARGUMENTS运行当前加载的程序。
示例:运行“ -I”“ hello world”
下一个 –用法:下一个逐步执行程序中的下一条语句。
步骤–用法:步骤
仅执行一条指令。
退出 –用法:退出退出GNU调试器。
断点断点告诉调试器暂停执行程序,直到您告诉它继续执行为止。 为了单步执行程序(即监视程序执行),应在要暂停执行的可执行语句上设置一个断点。 要在语句上设置断点,请使用
在(gdb)提示符下的break命令。 您可以指定函数名称或可执行文件的行号(如果知道的话)。确定所需的断点是调试的关键部分。 在程序执行中过早地设置断点,会浪费时间逐步浏览不需要调试的代码。 将断点设置得太晚,您可能会完全错过该错误。 在上面的示例程序中,我们的代码中有两个可能引起问题的位置。 get_choice函数未返回正确的值,或者is_valid_choice函数未正确检查该值。 让我们设置一个断点来检查get_choice函数的返回值。 有两个可能的地方检查值,一个地方在函数本身内部或在main的赋值语句中。 我们将在main中设置断点,以便我们可以检查返回值。 首先,我们将使用list命令在可执行文件中找到所需的行。 在我们的示例中,main从第26行开始,到第39行结束,因此该命令
清单26,39将在调试器中显示这些行: 注意 :行号可能会有所不同,具体取决于创建源文件的方式。 实验。在我们的示例中,用于设置断点的行是行号35。因此,键入以下命令
在(gdb)提示符下中断35 。 您应该看到类似于以下内容的屏幕: 观看程序执行设置断点后,使用以下命令启动调试器:
运行命令。 程序将开始运行,但在执行之前在带有断点的语句处暂停。 对于我们的示例,您应该看到类似以下屏幕的内容:此时,您有多种选择(详细信息如下)
1)了解执行程序中特定点的变量值通常会很有帮助。 调试器允许您在程序执行时查看变量的内容。 使用
打印命令以显示表达式或变量的值。2)如果当前语句是函数调用,请使用
步骤命令进入该函数以观看其执行。3)使用以下命令转到程序中的下一个语句
下一条命令。让我们使用print命令检查应用程序中的选择值。 注意,在下面的窗口中可供选择的值为char 0或NULL。 一旦get_choice函数返回一个值,我们将在下一节中再次检查它。
由于我们对进入get_choice函数不感兴趣,因此我们将使用
gdb提示符下的next命令在程序输入和输出中执行next语句您可能已经注意到,我们应用程序的输出出现在gdb控制台窗口中。 您应该会Swift询问
是否要继续(1 =是)(0 =否) ,输入0并按[Enter]。 现在,让我们再次选择使用print命令。 您应该看到类似于以下内容的屏幕:注意从之前的48和0而不是0和\ 0的变化。 48是字符0的ASCII值,因此get_choice函数正确地返回了一个字符值,而选择正确地存储了该值。 通过逐步执行程序,我们发现我们的错误不在get_choice函数中。 由于程序中的下一个语句是我们需要检查的另一个函数,is_valid_choice,并且我们知道有效的字符已存储在选择中,并且is_valid_choice函数应保持循环且没有错误消息。 使用step命令执行is_valid_choice函数。 注意我们的控制台窗口发生了什么。
这是不正确的,因为我们知道main中的以下语句将变量0中的字符0传递给了is_valid_choice函数:} while(!is_valid_choice(choice));。 因此,问题必须出在is_valid_choice检查值的方式上。 因此,我们将使用step命令执行该函数中的每个语句,以找出问题所在。 但是首先,您必须跳过几个语句才能再次进入is_valid_choice函数。 请注意,上面的控制台窗口左侧的行号是34。这表示当前语句。 在我们的示例中,cout语句显示“ Hello World…”消息。 键入下一步以执行此语句。 在“ next”旁边键入,再次执行第35行的get_choice函数语句。在控制台窗口中,在“您要继续吗”提示下键入1,然后按[Enter]继续执行程序。 现在键入step调试is_valid_choice函数。
请注意,屏幕左侧的行号在is_valid_choice函数内部的第90行,并且名为val的变量具有从main传递到实际参数选择中的值ASCII 49和'1'。
让我们通过键入列出接下来的10行
(gdb)提示符下列出90,100 。 注意,第93行是1的case语句。我们的程序应该执行第93行,因为val中有一个'1'。 再次键入step两次,请注意,行号一直跳到默认值:switch的一部分(行号96)内的第一个语句。它应该在看到以下内容后击中第94行的break语句
case 1:
break;
但这不是出于某种原因。
您在寻找什么
调试器最有用的方法有两种:1)验证语句是否按预期执行,以及2)验证变量是否具有预期值。 非常仔细地看一下case语句,我们似乎正在将整数1与字符“ 1”(ASCII中为49)进行比较,因此我们的程序运行正常,但逻辑测试不正确。 在is_valid_choice函数中更改case语句以查找字符数据:
switch (val){
case '0':
case '1':
break;
编辑代码以解决问题后,请保存更改,使用make dbg_main命令重建程序,然后使用gdb Debug / main.exe重新启动调试器。
键入break 35以再次为get_choice语句添加断点,然后键入run以像以前一样开始调试会话。
键入next,然后在出现提示时再次键入1,然后像以前一样在控制台窗口中按[Enter]。
再次键入next,请注意,这次,应用程序将像预期的那样跳到程序的末尾,第38行。
类型
杀在(GDB)提示来停止调试应用程序。此程序中还有一个逻辑问题,您应该使用相同的技术来查找它。 (提示:程序应继续打印“ Hello World…”,并要求用户在提示输入1时继续。)
解决方案这是严格的标准C解决方案...
///
/// \file main.c
/// \brief Some source code file Project Main Module
///
/// \author My Name
/// \version 00.99.00
/// \date January 1st, 2xxx
///
// History
// INI 2xxx-01-01 v1.00.00 Initial release
// Includes
#include <stdio.h>
#include <stdlib.h>
// Global constants and variables
#define PRG_NAME "MyProjectName1 - v 1.0.00"
#define CPY_RGHT "Copyright © 2xxx - "
#define AUTHOR "My Name"
// function prototypes
void show_copyright( void );
char get_choice( void );
unsigned int is_valid_choice( char );
// Uncomment to run just the testing main
//#define TEST 1
/
/// \fn main(int argc, char** argv)
/// \brief Main module for Hello World program.
///
/// \param argc - integer number of arguments passed from system to program
/// \param argv - pointer to array of characters of arguments passed to program from system
///
/// \return integer value for success or failure
/
#ifndef TEST
int main(int argc, char** argv)
{
int ret_val = 0; // holds return value for main program
char choice = '0';
show_copyright();
do{
do{
printf("Hello World...\n");
choice = get_choice();
}while(!is_valid_choice( choice));
}while(choice == '1');
return ret_val;
}
#else // Testing Main
int main( int argc, char** argv)
{
int ret_val = 0;
return ret_val;
}
#endif
/
/// \fn show_copyright(void)
/// \brief Show program name and copyright notice
///
/// \b SideEffects : None\n
/// \b Output : couts PRG_NAME, CPY_RGHT and AUTHOR defines\n
///
/// \return None
void show_copyright ( void )
{
printf("%s 's %s\n", AUTHOR, PRG_NAME);
printf("%s %s\n", CPY_RGHT, AUTHOR);
return;
}
/
/// \fn get_choice( void )
/// \brief Check to see if user wants to continue
///
/// \b SideEffects: None\n
/// \b Output: Prompts user to continue program\n
///
/// \param None
///
/// \return char ch - Choice entered by user
/
char get_choice( void )
{
char ret_val;
char ch;
printf("Do you want to continue (1 = Yes) (0 = No) ?: ");
fflush(stdin);
scanf("%c^%*",&ch);
ret_val = ch;
return ret_val;
}
/
/// \fn is_valid_choice( char val )
/// \brief Checks for valid yes or no entry to continue
///
/// \b SideEffects : None\n
/// \b Output : Displays an error message if an invalid choice is passed \n
///
/// \param val - Current choice to continue
///
/// \return boolean true if choice is valid and false otherwise
unsigned int is_valid_choice( char val )
{
unsigned int ret_val = 1;
switch (val){
case '0':
case '1':
break;
default:
ret_val = 0;
printf("Invalid choice : %c\n", val);
printf("Please enter one of the following(0 or 1) : \n");
break;
}
return ret_val;
}
C ++ with Streams解决方案
///
/// \file main.cpp
/// \brief Some source code file Project Main Module
///
/// \author My Name
/// \version 00.99.00
/// \date January 1st, 2xxx
///
// History
// INI 2xxx-01-01 v1.00.00 Initial release
// Includes
#include <iostream>
#include <iomanip>
using namespace std;
// Global constants and variables
const char PRG_NAME[] = {"MyProjectName1 - v 1.0.00"};
const char CPY_RGHT[] = {"Copyright © 2xxx - "};
const char AUTHOR[] = {"My Name"};
// function prototypes
void show_copyright( void );
char get_choice( void );
bool is_valid_choice( char );
// Uncomment to run just the testing main
//#define TEST 1
/
/// \fn main(int argc, char** argv)
/// \brief Main module for Hello World program.
///
/// \param argc - integer number of arguments passed from system to program
/// \param argv - pointer to array of characters of arguments passed to program from system
///
/// \return integer value for success or failure
/
#ifndef TEST
int main(int argc, char** argv)
{
int ret_val = 0; // holds return value for main program
char choice;
show_copyright();
do{
do{
cout << "Hello World..." << endl;
choice = get_choice();
}while(!is_valid_choice( choice));
}while(choice == '1');
return ret_val;
}
#else // Testing Main
int main( int argc, char** argv)
{
int ret_val = 0;
return ret_val;
}
#endif
/
/// \fn show_copyright(void)
/// \brief Show program name and copyright notice
///
/// \b SideEffects : None\n
/// \b Output : couts PRG_NAME, CPY_RGHT and AUTHOR defines\n
///
/// \return None
void show_copyright ( void )
{
cout << AUTHOR << "'s " << PRG_NAME << endl;
cout << CPY_RGHT << AUTHOR << endl << endl;
return;
}
/
/// \fn get_choice( void )
/// \brief Check to see if user wants to continue
///
/// \b SideEffects: None\n
/// \b Output: Prompts user to continue program\n
///
/// \param None
///
/// \return char ch - Choice entered by user
/
char get_choice( void )
{
char ret_val;
char ch;
cout << "Do you want to continue (1 = Yes) (0 = No) ?: ";
cin >> ch;
ret_val = ch;
return ret_val;
}
/
/// \fn is_valid_choice( char val )
/// \brief Checks for valid yes or no entry to continue
///
/// \b SideEffects : None\n
/// \b Output : Displays an error message if an invalid choice is passed \n
///
/// \param val - Current choice to continue
///
/// \return boolean true if choice is valid and false otherwise
bool is_valid_choice( char val )
{
bool ret_val = true;
switch (val){
case '0':
case '1':
break;
default:
ret_val = false;
cout << "Invalid choice : " << val << endl;
cout << "Please enter one of the following(0 or 1) : " << endl;
break;
}
return ret_val;
}
最后是带有类解决方案的C ++
main.cpp
///
/// \file main.cpp
/// \brief Some source code file Project Main Module
///
/// \author My Name
/// \version 00.99.00
/// \date January 1st, 2xxx
///
// History
// INI 2xxx-01-01 v1.00.00 Initial release
// Includes
#include <iostream>
#include <iomanip>
#include "oApp.h"
using namespace std;
// Uncomment to run just the testing main
//#define TEST 1
/
/// \fn main(int argc, char** argv)
/// \brief Main module for Hello World program.
///
/// \param argc - integer number of arguments passed from system to program
/// \param argv - pointer to array of characters of arguments passed to program from system
///
/// \return integer value for success or failure
/
#ifndef TEST
int main(int argc, char** argv)
{
int ret_val = 0; // holds return value for main program
oApp* myApp = new oApp;
myApp->init("Your Message Here...\n");
myApp->set_copyright("Copyright© 2006-2008 - ");
myApp->set_author("Your Name");
myApp->set_program_name("YourProgramName v00.99.00");
myApp->run();
myApp->done();
delete myApp;
return ret_val;
}
#else // Testing Main
int main( int argc, char** argv)
{
int ret_val = 0;
return ret_val;
}
#endif
应用程序
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
class oApp{
public:
oApp(){
m_choice = '0';
m_author = "My Name";
m_copyright = "Copyright © 2xxx - ";
m_program = "MyProjectName1 v1.0.00";
m_message = "Hello World...";
}
~oApp() {};
void init( const string s );
void run( void );
void done( void );
string get_copyright( void );
bool set_copyright( const string copyright );
string get_author( void );
bool set_author( const string author );
string get_program_name( void );
bool set_program_name( const string name );
void show_copyright( void );
private:
string m_author;
string m_program;
string m_copyright;
string m_message;
char m_choice;
char get_choice( void );
bool is_valid_choice( char val );
};
oApp.cpp
#include "oApp.h"
void oApp::init( const string s )
{
this->m_message = s;
}
void oApp::run( void )
{
show_copyright();
do{
do{
cout << this->m_message << endl;
this->m_choice = get_choice();
}while(!is_valid_choice( this->m_choice ));
}while(this->m_choice == '1');
}
void oApp::done( void ){}
string oApp::get_copyright( void )
{
string ret_val = this->m_copyright;
return ret_val;
}
bool oApp::set_copyright( const string copyright )
{
bool ret_val = false;
m_copyright = copyright;
ret_val = this->m_copyright == copyright;
return ret_val;
}
string oApp::get_author( void )
{
string ret_val = this->m_author;
return ret_val;
}
bool oApp::set_author( const string author )
{
bool ret_val = false;
m_author = author;
ret_val = this->m_author == author;
return ret_val;
}
string oApp::get_program_name( void )
{
string ret_val = this->m_program;
return ret_val;
}
bool oApp::set_program_name( const string name )
{
bool ret_val = false;
m_program = name;
ret_val = this->m_program == name;
return ret_val;
}
/
/// \fn get_choice( void )
/// \brief Check to see if user wants to continue
///
/// \b SideEffects: None\n
/// \b Output: Prompts user to continue program\n
///
/// \param None
///
/// \return char ch - Choice entered by user
/
char oApp::get_choice( void )
{
char ret_val;
char ch;
cout << "Do you want to continue (1 = Yes) (0 = No) ?: ";
cin >> ch;
ret_val = ch;
return ret_val;
}
/
/// \fn is_valid_choice( char val )
/// \brief Checks for valid yes or no entry to continue
///
/// \b SideEffects : None\n
/// \b Output : Displays an error message if an invalid choice is passed \n
///
/// \param val - Current choice to continue
///
/// \return boolean true if choice is valid and false otherwise
bool oApp::is_valid_choice( char val )
{
bool ret_val = true;
switch (val){
case '0':
case '1':
break;
default:
ret_val = false;
cout << "Invalid choice : " << val << endl;
cout << "Please enter one of the following(0 or 1) : " << endl;
break;
}
return ret_val;
}
/
/// \fn show_copyright(void)
/// \brief Show program name and copyright notice
///
/// \b SideEffects : None\n
/// \b Output : couts m_ProgramName, m_Copyright and m_Author\n
///
/// \return None
void oApp::show_copyright ( void )
{
cout << this->m_author << "'s " << this->m_program << endl;
cout << this->m_copyright << this->m_author << endl << endl;
return;
}
From: https://bytes.com/topic/c/insights/827839-zen-art-debugging-c-c-linux-gdb