Ansh 发布的文章

在本系列的第一部分中,我们通过讨论 cd - 命令的用法,重点介绍了 Linux 中的命令行导航。还讨论了一些其他相关要点/概念。现在进一步讨论,在本文中,我们将讨论如何使用 pushdpopd 命令在 Linux 命令行上获得更快的导航体验。

在我们开始之前,值得说明的一点是,此后提到的所有指导和命令已经在 Ubuntu 14.04 和 Bash shell(4.3.11)上测试过。

pushd 和 popd 命令基础

为了更好地理解 pushdpopd 命令的作用,让我们先讨论堆栈的概念。想象你厨房案板上有一个空白区域,你想在上面放一套盘子。你会怎么做?很简单,一个接一个地放在上面。

所以在整个过程的最后,案板上的第一个盘子是盘子中的最后一个,你手中最后一个盘子是盘子堆中的第一个。现在当你需要一个盘子时,你选择在堆的顶部的那个盘子并使用它,然后需要时选择下一个。

pushdpopd 命令是类似的概念。在 Linux 系统上有一个目录堆栈,你可以堆叠目录路径以供将来使用。你可以使用 dirs 命令来在任何时间点快速查看堆栈的内容。

下面的例子显示了在命令行终端启动后立即在我的系统上使用 dirs 命令的输出:

$ dirs
~

输出中的波浪号(~)表示目录堆栈当前仅包含用户的主目录。

继续下去,使用 pushdpopd 命令来执行存储目录路径并删除它的操作。使用 pushd 非常容易 - 只需将要存储在目录堆栈中的路径作为此命令的参数传递。这里有一个例子:

pushd /home/himanshu/Downloads/

上述命令的作用是,将当前工作目录更改为你作为参数传递的目录,并且还将路径添加到目录堆栈中。为了方便用户,pushd 命令在其输出中产生目录堆栈的内容。因此,当运行上面的命令时,产生了以下输出:

~/Downloads ~

输出显示现在堆栈中有两个目录路径:一个是用户的主目录,还有用户的下载目录。它们的保存顺序是:主目录位于底部,新添加的 Downloads 目录位于其上。

要验证 pushd 的输出是正确的,你还可以使用 dirs 命令:

$ dirs
~/Downloads ~

因此你可以看到 dirs 命令同样产生相同的输出。

让我们再使用下 pushd 命令:

$ pushd /usr/lib/; pushd /home/himanshu/Desktop/
/usr/lib ~/Downloads ~
~/Desktop /usr/lib ~/Downloads ~

所以目录堆栈现在包含总共四个目录路径,其中主目录(~)在底部,并且用户的桌面目录在顶部。

一定要记住的是堆栈的头是你当前的目录。这意味着现在我们当前的工作目录是 ~/Desktop

现在,假设你想回到 /usr/lib 目录,所以你所要做的就是执行 popd 命令:

$ popd
/usr/lib ~/Downloads ~

popd 命令不仅会将当前目录切换到 /usr/lib,它还会从目录堆栈中删除 ~/Desktop,这一点可以从命令输出中看出。这样,popd 命令将允许你以相反的顺序浏览这些目录。

一些高级用法

现在我们已经讨论了 pushdpopd 命令的基础知识,让我们继续讨论与这些命令相关的一些其它细节。首先,这些命令还允许你操作目录堆栈。例如,假设你的目录堆栈看起来像这样:

$ dirs
~/Desktop /usr/lib ~ ~/Downloads

现在,我们的要求是改变堆栈中目录路径的顺序,最上面的元素(~/Desktop)放到底部,剩下的每个都向上移动一个位置。这可以使用以下命令实现:

pushd +1

上面的命令对目录堆栈做的结果:

$ dirs
/usr/lib ~ ~/Downloads ~/Desktop

因此,我们看到目录堆栈中的元素顺序已经改变,并且现在和我们想要的一样。当然,你可以让目录堆栈元素移动任何次数。例如,以下命令会将它们向上移动两次:

$ pushd +2
~/Downloads ~/Desktop /usr/lib ~

你也可以使用负的索引值:

$ pushd -1
/usr/lib ~ ~/Downloads ~/Desktop

相似地,你可以在 popd 命令中使用此技术来从目录堆栈删除任何条目,而不用离开当前工作目录。例如,如果要使用 popd 从顶部(目前是 ~/Downloads)删除第三个条目,你可以运行以下命令:

popd +2

记住堆栈索引的初始值是 0,因此我们使用 2 来访问第三个条目。

因此目录堆栈现在包含:

$ dirs
/usr/lib ~ ~/Desktop

确认条目已经被移除了。

如果由于某些原因,你发现你很难记住元素在目录堆栈中的位置以及它们的索引,你则可以对在 dirs 命令中使用 -v 选项。这里有一个例子:

$ dirs -v
0 /usr/lib
1 ~
2 ~/Desktop

你可能已经猜到了,左边的数字是索引,接下来跟的是这个索引对应的目录路径。

注意: 在 dir 中使用 -c 选项清除目录堆栈。

现在让我们简要地讨论一下 popdpushd 命令的实际用法。虽然它们第一眼看起来可能有点复杂,但是这些命令在编写 shell 脚本时会派上用场 - 你不需要记住你从哪里来;只要执行一下 popd,你就能回到你来的目录。

经验丰富的脚本编写者通常以以下方式使用这些命令:

popd >/dev/null 2>&1

上述命令确保 popd 保持静默(不产生任何输出)。同样,你也可以静默 pushd

pushdpopd 命令也被 Linux 服务器管理员使用,他们通常在几个相同的目录之间移动。 在这里介绍了一些其他有用的使用场景。

总结

我同意 pushdpopd 的概念不是很直接。但是,它需要的只是一点练习 - 是的,你需要多实践。花一些时间在这些命令上,你就会开始喜欢它们,特别是当它们提供了方便时。


via: https://www.howtoforge.com/tutorial/linux-command-line-tips-tricks-part-2/

作者:Ansh 译者:geekpi 校对:jasminepeng

本文由 LCTT 原创编译,Linux中国 荣誉推出

目前为止,在一系列介绍 vim 插件文章中,我们介绍了使用 Pathogen 插件管理包安装基本的 vim 插件,也提及了另外三个插件:Tagbar、delimitMateSyntastic。现在,在最后一部分,我们将介绍另一个十分有用的插件 a.vim。

请注意所有本篇教程所提及的例子、命令和指导,它们已经在 Ubuntu 16.04 测试完毕,vim 使用版本为 vim7.4 (LCTT 译注:Ubuntu 16.04 的默认版本)。

A.vim

如果你一直用像 C、C++ 这样的语言进行开发工作,你一定有这样的感触:我特么已经数不清我在头文件和源代码之间切换过多少次了。我想说的是,确实,这个操作十分基本,十分频繁。

尽管使用基于 GUI(图形界面)的 IDE(集成开发环境)非常容易通过鼠标的双击切换文件,但是如果你是资深 vim 粉,习惯用命令工作就有点尴尬了。但是不要害怕,我有秘籍--插件 a.vim。它可以让你解决尴尬,专治各种文件切换。

在我们介绍这个神器用法之前,我必须强调一点:这个插件的安装过程和我们其他篇介绍的不太一样,步骤如下:

  • 首先,你需要下载两个文件(a.vimalternate.txt),你可以在这里找到它们。
  • 接下来,创建如下目录:~/.vim/bundle/avim~/.vim/bundle/avim/doc~/.vim/bundle/avim/plugin~/.vim/bundle/autoload
  • 创建好目录之后,将 a.vim 放到 ~/.vim/bundle/avim/plugin~/.vim/bundle/autoload,以及将 alternate.txt 放到 ~/.vim/bundle/avim/doc

就是这样,如果上述步骤被你成功完成,你的系统就会安装好这个插件。

使用这个插件十分简单,你仅仅需要运行这个命令 :A 如果目前的文件是源文件(比如 test.c),这个神器就会帮你打开 test.c 对应的头文件(test.h),反之亦然。

当然咯,不是每个文件对应的头文件都存在。这种情况下,如果那你运行 :A 命令,神器就会为你新建一个文件。比如,如果 test.h 不存在,那么运行此命令就会帮你创建一个 test.h,然后打开它。

如果你不想要神器开启此功能,你可以在你的家目录的隐藏文件 .vimrc 中写入 g:alternateNonDefaultAlternate 变量,并且赋给它一个非零值即可。

还有一种情况也很普遍,你需要打开的文件并非是当前源代码的头文件。比如你目前在 test.c 你想打开 men.h 这个头文件,那么你可以输入这个命令 :IH <filename> ,毋需赘言,你肯定要在后面输入你要打开的的文件名称 <filename>

目前为止,我们讨论的功能都仅限于你当前文件和要操作的文件都在同一个目录去实现。但是,你也知道,我们还有特殊情况,我是说,许多项目中头文件与对应的源文件并不一定在同一目录下。

为了搞定这个问题,你要使用这个 g:alternateSearchPath 这个变量。官方文档是这么解释的:

这个插件可以让用户配置它的搜索源文件和头文件的搜索路径。这个搜索路径可以通过设置 g:alternateSearchPath 这个变量的值指定。默认的设定如下:

g:alternateSearchPath = 'sfr:../source,sfr:../src,sfr:../include,sfr:../inc' 

使用这个代码表示神器将搜索 ../source../src../include../inc 下所有与目标文件相关的文件。 g:alternateSearchPath 变量的值由前缀和路径组成,每个单元用逗号隔开。 sfr 前缀是指后面的路径是相对于目前文件的,wdr 前缀是指目录是相对于目前的工作目录, abs 是指路径是绝对路径。如果不指定前缀,那么默认为 sfr

如果我们前文所提及的特性就能让你觉得很炫酷,那我不得不告诉你,这才哪跟哪。还有一个十分有用的功能是分割 Vim 屏幕,这样你就可以同时看到头文件和相应的源文件。

哦,还有,你还可以选择垂直或者水平分割。全凭你心意。使用 :AS 命令可以水平分割,使用 :AV 可以垂直分割。

Vim.a vertical split screen

vim.a horizontal split screen

使用 :A 命令在已经打开的文件中切换。

这个插件还可以让你在同一个 Vim 窗口中不同选项卡中打开多个相应的文件,你键入这个命令 :AT

tabs in Vim with a.vim.

当然,你可以用这些命令 :AV:AS:AT,也可以使用这些命令 :IHV:IHS:IHT

最后

还有许多和编程相关的 Vim 的插件,我们在这个三篇系列主要讨论的是,如果你为你的软件开发工作安装了合适的插件,你就会明白为什么 vim 被叫做编辑器之神。

当然,我们在这只关注编程方面,对于那些把 Vim 当做日常文档编辑器的人来说,你也应该了解一些 Vim 的插件,让你的编辑更好,更高效.我们就改日再谈这个问题吧。


via: https://www.howtoforge.com/tutorial/vim-editor-plugins-for-software-developers-3/

作者:Ansh 译者:Taylor1024 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

不用我说,你也知道 GIF 动画在过去几年发展迅速。人们经常在线上文字交流时使用动画增添趣味,同时这些动画在很多其他地方也显得非常有用。

在技术领域使用动画能够很快的描述出现的问题或者返回的错误。它也能很好的展现出一个软件应用产品的特性。你可以在进行线上座谈会或者在进行公司展示时使用 GIF 动画,当然,你可以在更多的地方用到它。

现在,假设你的电脑桌面上打开了多个应用程序,或者无论出于什么目的,你想制作一个 GIF 动画来记录桌面上一个应用程序窗口的操作过程。你应该怎么做呢?显然,你需要一个工具来完成这件事。

如果你正在寻找了这样一个可以记录桌面上部分区域的工具,并且它可以自动把录屏转化成 GIF 动画; 现在,本教程会介绍一个 Linux 命令行工具来实现你的需求。

开始之前,你必须知道在本教程中所有的例子都是在 Ubuntu 14.04 上测试过的,它的 Bash 版本是 4.3.11(1) 。

Gifine

这个工具的主页是 Gifine 。它基于 GTK 工具包,是用 MoonScript 使用 lgi 库编写的。Gifine 不仅能够录屏、创建动画或视频,而且能够用它来把几个小型动画或视频拼接在一起。

引述这个工具的开发者的话:“你可以加载一个视频帧的目录或者选择一个桌面的区域进行录屏。你加载了一些视频帧后,可以连续查看它们,并裁剪掉不需要的部分。最终完成录屏后可以导出为 gif 或者 mp4 文件。”

Gifine 下载/安装/配置

在指引你下载和安装 Gifine 之前,应该指出安装这个工具时需要安装的依赖包。

首先需要安装的依赖包是 FFmpeg , 这个软件包是一种记录、转化和流化音频以及视频的跨平台解决方案。使用下列命令安装这个工具;

sudo apt-get install ffmpeg

接下来是图像处理系统 GraphicsMagick。这个工具的官网说:“它提供了一个稳健且高效的工具和库的集合,支持读写并且可以操作超过 88 种主要的图像格式,比如:DPX、 GIF、 JPEG、 JPEG-2000、 PNG、 PDF、 PNM 以及 TIFF 等。”

通过下面的命令安装:

sudo apt-get install graphicsmagick

接下来的需要的工具是 XrectSel 。在你移动鼠标选择区域的时候,它会显示矩形区域的坐标位置。我们只能通过源码安装 XrectSel ,你可以从 这里 下载它。

如果你下载了源码,接下来就可以解压下载的文件,进入解压后的目录中。然后,运行下列命令:

./bootstrap

如果 configure 文件不存在,就需要使用上面的命令

./configure --prefix /usr

make

make DESTDIR="$directory" install

最后的依赖包是 Gifsicle 。这是一个命令行工具,可以创建、编辑、查看 GIF 图像和动画的属性信息。下载和安装 Gifsicle 相当容易,你只需要运行下列命令:

sudo apt-get install gifsicle

这些是所有的依赖包。现在,我们开始安装 Gifine 。使用下面的命令完成安装。

sudo apt-get install luarocks

sudo luarocks install --server=http://luarocks.org/dev gifine

请注意第二个命令可能会返回下列错误:

No package 'gobject-introspection-1.0' found

你可以用下列命令安装这个包:

sudo apt-get install libgirepository1.0-dev

然后,再一次运行 luarocks install 命令。

Gifine 使用

完成安装之后可以使用下面的命令运行这个工具:

gifine

这个应用程序的 UI 是这样的:

Gifine UI

这里你可以进行两种操作:录视频帧或者加载视频帧。如果你单击了 录制矩形区域 Record rectange 按钮,你的鼠标指针处会变成一个 + ,这样便可以在你的屏幕上选择一个矩形区域。一旦你选择了一个区域,录屏就开始了, 录制矩形区域 Record rectange 按钮就会变成 停止录制 Stop recording 按钮。

Gifine screen recording

单击 停止录制 Stop recording 完成录屏,会在 Gifine 窗口出现一些按钮。

Gifine preview

用户界面的上半部分显示已经录制的视频帧,你可以使用它下面的滑块进行逐帧浏览。如果你想要删除第 5 帧之前或第 50 帧之后的所有帧数,你可以使用 裁剪左边 Trim left of 裁剪右边 Trim rigth of 按钮进行裁剪。也有可以删除特定帧数和减半删除帧数的按钮,当然,你可以重置所有的裁剪操作。

完成了所有的裁剪后,可以使用 保存 GIF Save GIF... 保存 MP4 Save MP4... 按钮将录屏保存为动画或者视频;你会看到可以设置帧延迟、帧率以及循环次数的选项。

记住,“录屏帧不会自动清除。如果你想重新加载,可以在初始屏幕中使用 加载目录 load directory 按钮在 '/tmp' 目录中找到它们。“

总结

Gifine 的学习曲线并不陡峭 —— 所有的功能都会以按钮、文本的形式体现出来。

对我来说,最大的问题是安装 —— 需要一个个安装它的依赖包,还要处理可能出现的错误,这会困扰很多人。否则,从整体上看,Gifine 绝对称得上是一个不错的工具,如果你正在寻找这样的工具,不妨一试。

已经是 Gifine 用户?到目前为止你得到了什么经验?在评论区告诉我们。


via: https://www.howtoforge.com/tutorial/record-screen-to-animated-gif-on-linux/

作者:Ansh 译者:vim-kakali 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

相关内容

如果你刚开始在 Linux 系统中使用命令行工具,那么你应该知道它是 Linux 操作系统中功能最强大和有用的工具之一。学习的难易程度跟你想研究的深度有关。但是,无论你的技术能力水平怎么样,这篇文章中的一些小贴士和技巧都会对你有所帮助。

在本系列的文章中,我们将会讨论一些非常有用的命令行工具使用小技巧,希望你的命令行使用体验更加愉快。

但是在开始下一步之前,我得强调一点,这篇文章中的测试实例都是在 Ubuntu 14.04LTS 系统下测试通过的。我们使用命令行 Shell 版本是 bash 4.3.11 。

Linux 命令行工具使用的一些小技巧

我们假设你已经掌握了一些 Linux 命令行的基础知识,比如什么是 root 账号及 home 目录,什么是环境变量,如何查看目录内容等等。说明这些小技巧的同时也会介绍涉及到的概念,如果有的话。

轻松切换目录 —— 快捷方式

假设你正在命令行下做一些操作,并且你需要经常在两个目录间来回切换。而且这两个目录在完全不同的两个路径下,比如说,分别在 /home//usr/ 下。你会怎么做呢?

其中,最简单直接的方式就是输入这些目录的全路径。虽然这种方式本身没什么问题,但是却很浪费时间。另外一种方式就是打开两个终端窗口分别进行操作。但是这两种方式使用起来既不方便,也显得没啥技术含量。

你应该感到庆幸的是,还有另外一种更为简捷的方法来解决这个问题。你需要做的就是先手动切换到这两个目录(通过 cd 命令分别加上各自的路径),之后你就可以使用 cd - 命令在两个目录之间来回快速切换了。

例如:

我现在在下面的目录:

$ pwd
/home/himanshu/Downloads

然后,我切换到 /usr/ 路径下的其它目录:

cd /usr/lib/

现在,我可以很方便的使用下面的命令来向前、向后快速地切换到两个目录:

cd -

下面是 cd - 命令的操作截图:

The Linux cd command

有一点我得跟大家强调下,如果你在操作的过程中使用 cd 加路径的方式切换到第三个目录下,那么 cd - 命令将应用于当前目录及第三个目录之间进行切换。

轻松切换目录 —— 相关细节

对于那些有强烈好奇心的用户,他们想搞懂 cd - 的工作原理,解释如下:如大家所知道的那样, cd 命令需要加上一个路径作为它的参数。现在,当 - 符号作为参数传输给 cd 命令时,它将被 OLDPWD 环境变量的值所替代。

The cd command explained

现在应该明白了吧, OLDPWD 环境变量存储的是前一个操作目录的路径。这个解释在 cd 命令的 man 帮助文档中有说明,但是,很遗憾的是你的系统中可能没有预先安装 man 命令帮助工具(至少在 Ubuntu 系统下没有安装)。

但是,安装这个 man 帮助工具也很简单,你只需要执行下的安装命令即可:

sudo apt-get install manpages-posix

然后做如下操作:

man cd

打开 man 帮助文档主页后,你将会看到下面很明确的解释:

—— 当 - 符号被用作 cd 命令的参数值时,将等同于下面的操作命令:

 cd "$OLDPWD" && pwd

毫无疑问, cd 命令设置了 OLDPWD 环境变量值。因此每一次你切换操作目录时,上一个目录的路径就会被保存到这个变量里。这还让我们看到很重要的一点就是:任何时候启动一个新的 shell 实例(包括手动执行或是使用 shell 脚本),都不存在 ‘上一个工作目录’。

Hyphen and the cd command

这也很符合逻辑,因为 cd 命令设置了 OLDPWD 环境变量值。因此,除非你至少执行了一次 cd 命令,否则 OLDPWD 环境变量不会包含任何值。

继续,尽管这有些难以理解, cd -cd $OLDWPD 命令的执行结果并非在所有环境下都相同。比如说,你重新打开一个新的 shell 窗口时。

cd command example

从上面的截图可以清楚的看出,当执行 cd - 命令提示未设置 OLDPWD 值时, cd $OLDPWD 命令没有报任何错;实际上,它把当前的工作目录改变到用户的 home 目录里。

那是因为 OLDPWD 变量目前还没有被设置, $OLDPWD 仅仅是一个空字符串。因此, cd $OLDPWD 命令跟 cd 命令的执行结果是一致的,默认情况下,会把用户当前的工作目录切换到用户的 home 目录里。

最后,我还遇到过这样的要求,需要让 cd - 命令执行的结果不显示出来。我的意思是,有这样的情况(比如说,在写 shell 脚本的时候),你想让 cd - 命令的执行结果不要把目录信息显示出来。那种情况下,你就可以使用下面的命令方式了:

cd - &>/dev/null

上面的命令把文件描述符 2(标准错误)和 1(标准输出)的结果重定向到 /dev/null 目录。这意味着,这个命令产生的所有的错误不会显示出来。但是,你也可以使用通用的 $? 方式来检查这个命令的执行是否异常。如果这个命令执行报错, echo $? 将会返回 1,否则返回 0

或者说,如果你觉得 cd - 命令出错时输出信息没有关系,你也可以使用下面的命令来代替:

cd - > /dev/null

这个命令仅用于将文件描述符 1 (标准输出)重定向到 /dev/null

总结

遗憾的是,这篇文章仅包含了一个跟命令行相关的小技巧,但是,我们已经地对 cd - 命令的使用进行了深入地探讨。建议你在自己的 Linux 系统的命令行终端中测试本文中的实例。此外,也强烈建议你查看 man 帮助文档,然后对 cd 命令进行全面测试。

如果你对这篇文章有什么疑问,请在下面的评论区跟大家交流。同时,敬请关注下一篇文章,我们将以同样的方式探讨更多有用的命令行使用技巧。


via: https://www.howtoforge.com/tutorial/linux-command-line-navigation-tips-and-tricks-part-1/

作者:Ansh 译者:rusking 校对:jasminepeng

本文由 LCTT 原创编译,Linux中国 荣誉推出

无论多么有经验的程序员,开发的任何软件都不可能完全没有 bug。因此,排查及修复 bug 成为软件开发周期中最重要的任务之一。有许多办法可以排查 bug(测试、代码自审等等),但是还有一些专用软件(称为调试器)可以帮助准确定位问题的所在,以便进行修复。

如果你是 C/C++ 程序员,或者使用 Fortran 和 Modula-2 编程语言开发软件,那么你将会很乐意知道有这么一款优秀的调试器 - GDB - 可以帮你更轻松地调试代码 bug 以及其它问题。在这篇文章中,我们将讨论一下 GDB 调试器的基础知识,包括它提供的一些有用的功能/选项。

在我们开始之前,值得一提的是,文章中的所有说明和示例都已经在 Ubuntu 14.04 LTS 中测试过。教程中的示例代码都是 C 语言写的;使用的 shell 为 bash(4.3.11);GDB 版本为 7.7.1。

GDB 调试器基础

通俗的讲,GDB 可以让你看到程序在执行过程时的内部流程,并帮你明确问题的所在。我们将在下一节通过一个有效的示例来讨论 GDB 调试器的用法,但在此之前,我们先来探讨一些之后对你有帮助的基本要点。

首先,为了能够顺利使用类似 GDB 这样的调试器,你必须以指定的方式编译程序,让编译器产生调试器所需的调试信息。例如,在使用 gcc 编译器(我们将在本教程之后的章节用它来编译 C 程序示例)编译代码的时候,你需要使用 -g 命令行选项。

想要了解 gcc 编译器手册页中关于 -g 命令行选项相关的内容,请看这里

下一步,确保在你的系统中已经安装 GDB 调试器。如果没有安装,而且你使用的是基于 Debian 的系统(如 Ubuntu),那么你就可以使用以下命令轻松安装该工具:

sudo apt-get install gdb

在其他发行版上的安装方法,请看这里

现在,当你按照上述的方式编译完程序(gcc -g 命令行选项),同时也已经安装好 GDB 调试器,那么你就可以使用以下命令让程序在调试模式中运行:

gdb [可执行程序的名称]

这样做会初始化 GDB 调试器,但你的可执行程序此时还不会被启动。在这个时候你就可以定义调试相关的设置。例如,你可以在特定行或函数中设置一个断点让 GDB 在该行暂停程序的执行。

接着,为了启动你的程序,你必须输入执行以下 gdb 命令:

run

在这里,值得一提的是,如果你的程序需要一些命令行参数,那么你可以在这里指定这些参数。例如:

run [参数]

GDB 提供了很多有用的命令,在调试的时候总是能派的上用场。我们将在下一节讨论其中一部分命令。

GDB 调试器用例

现在我们对 GDB 及其用法有了基本的概念。因此,让我们举例来应用所学的知识。这是一段示例代码:

#include <stdio.h>

int main()
{
    int out = 0, tot = 0, cnt = 0;
    int val[] = {5, 54, 76, 91, 35, 27, 45, 15, 99, 0};

    while(cnt < 10)
    {
        out = val[cnt];
        tot = tot + 0xffffffff/out;
        cnt++;
    }

    printf("\n Total = [%d]\n", tot);
    return 0;
}

简单说明一下这段代码要做什么事。获取 val 数组中每一个值,将其赋值给 out 变量,然后将 tot 之前的值与 0xffffffff/out 的结果值累加,赋值给 tot 变量。

这里遇到的问题是,当执行这段代码编译后的可执行程序时,产生以下错误:

$ ./gdb-test
Floating point exception (core dumped)

因此,要调试这段代码,第一步是使用 -g 选项编译程序。命令如下:

gcc -g -Wall gdb-test.c -o gdb-test

接着,让我们运行 GDB 调试器并指定要调试的可执行程序。命令如下:

gdb ./gdb-test

现在,我刚才得到的错误是 Floating point exception,大部分人可能已经知道,这是因为 n % x,当 x 为 0 时导致的错误。所以,考虑到这一点,我在 11 行代码除法运算的位置处添加了一个断点。如下:

(gdb)&;break 11

注意 (gdb) 是调试器的提示信息,我只输入了 break 11 命令。

现在,让 GDB 开始运行程序:

run

当断点第一次被命中时,GDB 显示如下输出:

Breakpoint 1, main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
(gdb)

正如你所看到的那样,调试器会显示断点所在的行代码。现在,让我们打印出此时 out 的值。如下:

(gdb) print out
$1 = 5
(gdb)

如上所示,值 5 被打印出来了。这个时候一切都还是正常的。让调试器继续执行程序直到命中下一个断点,可以通过使用 c 命令来完成:

c

重复上述操作,直到 out 值变为 0 时。

...
...
...
Breakpoint 1, main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
(gdb) print out
$2 = 99
(gdb) c
Continuing.

Breakpoint 1, main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
(gdb) print out
$3 = 0
(gdb)

现在,为了进一步确认问题,我使用 GDB 的 s(或 step) 命令代替 c 命令。因为,我只想让当前程序在第 11 行之后暂停,再一步步执行,看看这个时候是否会发生崩溃。

以下是执行之后输出信息:

(gdb) s

Program received signal SIGFPE, Arithmetic exception.
0x080484aa in main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;

是的,如上输出的第一行内容所示,这就是抛出异常的地方。当我再次尝试运行 s 命令时,问题最终也得到了确认:

(gdb) s

Program terminated with signal SIGFPE, Arithmetic exception.
The program no longer exists.

通过这种方式,你就可以使用 GDB 调试你的程序。

总结

GDB 提供了很多功能供用户研究和使用,在这里,我们仅仅只介绍了很少一部分内容。通过 GDB 的手册页可以进一步了解这个工具,当你在调试代码的时候,尝试使用一下它。GDB 调试器有一定的学习难度,但是它很值得你下功夫学习。


via: https://www.howtoforge.com/tutorial/how-to-debug-c-programs-in-linux-using-gdb/

作者:Ansh 译者:zhb127 校对:jasminepeng

本文由 LCTT 原创编译,Linux中国 荣誉推出

gcc 编译器提供了几乎数不清的命令行选项列表。当然,没有人会使用过或者精通它所有的命令行选项,但是有一些命令行选项是每一个 gcc 用户都应该知道的 - 即使不是必须知道。它们中有一些很常用,其他一些不太常用,但不常用并不意味着它们的用处没前者大。

在这个系列的文章中,我们集中于一些不常用但是很有用的 gcc 命令行选项,在第一节已经讲到几个这样的命令行选项。

不知道你是否能够回想起,在这个系列教程的第一部分的开始,我简要的提到了开发者们通常用来生成警告的 -Wall 选项,并不包括一些特殊的警告。如果你不了解这些特殊警告,并且不知道如何生成它们,不用担心,我将在这篇文章中详细讲解关于它们所有的细节。

除此以外,这篇文章也将涉及与浮点值相关的 gcc 警告选项,以及在 gcc 命令行选项列表变得很大的时候如何更好的管理它们。

在继续之前,请记住,这个教程中的所有例子、命令和指令都已在 Ubuntu 16.04 LTS 操作系统和 gcc 5.4.0 上测试过。

生成 -Wall 选项不包括的警告

尽管 gcc 编译器的 -Wall 选项涵盖了绝大多数警告标记,依然有一些警告不能生成。为了生成它们,请使用 -Wextra 选项。

比如,下面的代码:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int i=0;
    /* ...
       some code here 
       ...
    */

    if(i);
        return 1;
     return 0; 
}

我不小心在 if 条件后面多打了一个分号。现在,如果使用下面的 gcc 命令来进行编译,不会生成任何警告。

gcc -Wall test.c -o test

但是如果同时使用 -Wextra 选项来进行编译:

gcc -Wall -Wextra test.c -o test

会生成下面这样一个警告:

test.c: In function ‘main’:
test.c:10:8: warning: suggest braces around empty body in an ‘if’ statement [-Wempty-body]
 if(i);

从上面的警告清楚的看到, -Wextra 选项从内部启用了 -Wempty-body 选项,从而可以检测可疑代码并生成警告。下面是这个选项启用的全部警告标记。

  • -Wclobbered
  • -Wempty-body
  • -Wignored-qualifiers
  • -Wmissing-field-initializers
  • -Wmissing-parameter-type (仅针对 C 语言)
  • -Wold-style-declaration (仅针对 C 语言)
  • -Woverride-init
  • -Wsign-compare
  • -Wtype-limits
  • -Wuninitialized
  • -Wunused-parameter (只有和 -Wunused-Wall 选项使用时才会启用)
  • -Wunused-but-set-parameter (只有和-Wunused-Wall` 选项使用时才会生成)

如果想对上面所提到的标记有更进一步的了解,请查看 gcc 手册

此外,遇到下面这些情况, -Wextra 选项也会生成警告:

  • 一个指针和整数 0 进行 <<=>, 或 >= 比较
  • (仅 C++)一个枚举类型和一个非枚举类型同时出现在一个条件表达式中
  • (仅 C++)有歧义的虚拟基底
  • (仅 C++)寄存器类型的数组加下标
  • (仅 C++)对寄存器类型的变量进行取址
  • (仅 C++)基类没有在派生类的复制构建函数中进行初始化

浮点值的等值比较时生成警告

你可能已经知道,浮点值不能进行确切的相等比较(如果不知道,请阅读与浮点值比较相关的 FAQ)。但是如果你不小心这样做了, gcc 编译器是否会报出错误或警告?让我们来测试一下:

下面是一段使用 == 运算符进行浮点值比较的代码:

#include<stdio.h>

void compare(float x, float y)
{
    if(x == y)
    {
        printf("\n EQUAL \n");
    }
}

int main(void)
{
    compare(1.234, 1.56789);

    return 0; 
}

使用下面的 gcc 命令(包含 -Wall-Wextra 选项)来编译这段代码:

gcc -Wall -Wextra test.c -o test

遗憾的是,上面的命令没有生成任何与浮点值比较相关的警告。快速看一下 gcc 手册,在这种情形下可以使用一个专用的 -Wfloat-equal 选项。

下面是包含这个选项的命令:

gcc -Wall -Wextra -Wfloat-equal test.c -o test

下面是这条命令产生的输出:

test.c: In function ‘compare’:
test.c:5:10: warning: comparing floating point with == or != is unsafe [-Wfloat-equal]
 if(x == y)

正如上面你所看到的输出那样, -Wfloat-equal 选项会强制 gcc 编译器生成一个与浮点值比较相关的警告。

这儿是gcc 手册关于这一选项的说明:

这背后的想法是,有时,对程序员来说,把浮点值考虑成近似无限精确的实数是方便的。如果你这样做,那么你需要通过分析代码,或者其他方式,算出这种计算方式引入的最大或可能的最大误差,然后进行比较时(以及产生输出时,不过这是一个不同的问题)允许这个误差。特别要指出,不应该检查是否相等,而应该检查两个值是否可能出现范围重叠;这是用关系运算符来做的,所以等值比较可能是搞错了。

如何更好的管理 gcc 命令行选项

如果在你使用的 gcc 命令中,命令行选项列表变得很大而且很难管理,那么你可以把它放在一个文本文件中,然后把文件名作为 gcc 命令的一个参数。之后,你必须使用 @file 命令行选项。

比如,下面这行是你的 gcc 命令:

gcc -Wall -Wextra -Wfloat-equal test.c -o test

然后你可以把这三个和警告相关的选项放到一个文件里,文件名叫做 gcc-options

$ cat gcc-options&nbsp;
-Wall -Wextra -Wfloat-equal

这样,你的 gcc 命令会变得更加简洁并且易于管理:

gcc @gcc-options test.c -o test

下面是 gcc 手册关于 @file 的说明:

从文件中读取命令行选项。读取到的选项随之被插入到原始 @file 选项所在的位置。如果文件不存在或者无法读取,那么这个选项就会被当成文字处理,而不会被删除。

文件中的选项以空格分隔。选项中包含空白字符的话,可以用一个由单引号或双引号包围完整选项。任何字符(包括反斜杠: '\')均可能通过一个 '\' 前缀而包含在一个选项中。如果该文件本身包含额外的 @file 选项,那么它将会被递归处理。

结论

在这个系列的教程中,我们一共讲解了 5 个不常见但是很有用的 gcc 命令行选项: -Save-temps-g-Wextra-Wfloat-equal 以及 @file。记得花时间练习使用每一个选项,同时不要忘了浏览 gcc 手册上面所提供的关于它们的全部细节。

你是否知道或使用其他像这样有用的 gcc 命令行选项,并希望把它们在全世界范围内分享?请在下面的评论区留下所有的细节。


via: https://www.howtoforge.com/tutorial/uncommon-but-useful-gcc-command-line-options-2/

作者:Ansh 译者:ucasFL 校对:jasminepeng

本文由 LCTT 原创编译,Linux中国 荣誉推出