GDB 命令详解

连接 Linux 服务器的时候,一般无法直接使用 IDE 工具来帮助我们调试代码,只好求助于 GDB 了。GDB 调试并不难,也不比 IDE 调试复杂多少,唯一要做的只不过是多记住一些调试命令而已。

以 C 代码为例。假设我们编写了一个源文件 test.c,那么,要使用 GDB 调试,首先要把源代码编译成可执行文件。当然,调试信息肯定是要打开的,打开方式一般就是在 gcc 命令中使用 -g 参数。例如:

$ gcc test.c -o test.out -g

有了编译后的可执行文件 test.out 后,就可以让 GDB 程序运行可执行文件进行调试了:

$ gdb test.out

GDB 的命令虽多,但结合我们使用 IDE 的经验,一般需要用到的命令也就那么几个。本文就罗列出常用的一些调试命令,供大家查询使用。

阅读余文GDB 命令详解

匿名命名空间

在 C/C++ 的源文件中,为了对外隔离符号,即外界无法通过 extern 声明捕获到这个符号,我们一般会采用 static 声明的方式来处理这个符号。比如

// 采用static声明对外隐藏符号
static void internal_func();

static float internal_value;

这样, internal_funcinternal_value 这两个符号对外就是不可见的了。一般情况下,隐藏符号只通过 static 声明就可以了,但 static 声明也有如下缺点:

1、static 无法修饰类型,比如这样的类型声明就是错误的。

// 注意:这段代码是非法的
static class Widget {
public:
    ...
};

因此,如果想要隐藏 Widget 这个类,就不能用 static 声明的方式。

2、static 这个关键词用处过多,在不同的地方修饰的变量,其含义完全不同,容易造成混淆。比如下面定义的三个 static 变量,其含义就完全不同

class Widget
{
private:
    static float count;
};

static const float PI = 3.141592654;

void test()
{
    static int i = 0;
    ...
}

3、由于 static 声明会使得符号没有外部链接属性,因此某些模板参数将不能使用这个符号,比如

template<typename T, const int& N>
class Widget
{
public:
    ...
private:
    T data[N];
    ...
};

static const int kMaxSize = 30;

Widget<int, kMaxSize> w;   // 报错,因为kMaxSize并不具备外部链接属性

为了克服上述三个缺点,就需要引入另一种隐藏符号的方式——匿名命名空间。我们先来看这样一段声明

// 采用匿名命名空间对外隐藏符号
namespace {

void internal_func();

float internal_value;

}

在这段声明中,注意我们并没有指定 namespace 是什么。这种没有为 namespace 指定名字的命名空间就是所谓的“匿名命名空间”。

阅读余文匿名命名空间

calloc 和 malloc 的区别

在 C 语言中,从堆(heap)中动态分配内存一般有两种方式,一种是通过 calloc,另一种是通过 malloc。那么这两种动态分配内存的方式有什么区别呢?

阅读余文calloc 和 malloc 的区别

C/C++ 函数指针

函数指针是一个指向函数地址的指针,未来可以通过函数指针来调用函数。可以把函数指针的定义理解为一种协议代理机制。函数指针定义了函数应该长什么样,需要什么参数,会得到何种返回值。这就相当于定义了一个协议。不同的代理人根据这一层协议,去实现自己的函数体,也即实现自己的代理行为。不同的代理人可以把自己的函数体传递给函数指针的调用者,调用者并不关心是谁代理了这个协议,只要传递给他的是一个合法的非空指针的协议,就可以在合适的时机去执行这个函数体。从这个意义上来说,函数指针的一大好处就是封装了行为。

那么,函数指针具体是如何定义的,调用者是如何调用函数指针传进来的函数体的?这篇文章就通过几个例子来说明函数指针的用法。

阅读余文C/C++ 函数指针