Linux C/C++编程FAQ系列 之三

Posted by c4pr1c3 on November 29, 2010

如何使用core dump文件来定位程序出错位置和出错信息?

编译时找不到名为 foo.h 的头文件?

我明明已经包含了 foo.h, 怎么编译时还报 undefined reference to ‘foo’?

想看下 Linux 下一些命令的源码,找不到

如何找到某个命令是属于哪个包的

Linux 如何支持大文件(单个文件大于2GB)的I/O操作?


如何使用core dump文件来定位程序出错位置和出错信息?

step 1: 加载可执行文件崩溃时所产生的core dump文件

gdb -c

或者,可以在gdb启动之后使用命令

target core

step 2: 定位程序错误

(gdb) where

#0  0x0804bffd in IP_CheckSum (psIPHeader=0xe) at public_protocol_analyse.c:145
#1  0x0804c086 in IP_HandleHeadInfo (psIPHeader=0xe) at public_protocol_analyse.c:179
#2  0x08051f55 in Handle_IPLayer (pcPktIP=0xe 

) at interface.c:41 #3  0x0804a4c6 in preProcessPkt (args=0x8f82138) at t_mmain.c:267 #4  0xb7f7c50f in start_thread () from /lib/tls/i686/cmov/libpthread.so.0 #5  0xb7ef8a0e in clone () from /lib/tls/i686/cmov/libc.so.6 </pre>

从上面的例子中可以看到程序的出错位置(具体到源代码中的位置)和出错信息(出错时的函数堆栈调用信息)一目了然。当然,之所以能够定位程序出错信息到具体的源代码级别,必须要在程序编译时加入调试信息(如gcc使用-g参数),否则无法获得源代码级别的详细信息。

除了where之外,更“正统”的函数调用堆栈信息查询命令是backtrace(简写为bt)或info stack。如果查看某一个具体函数栈帧的信息,可以使用GDB命令frame 。

编译时找不到名为 foo.h 的头文件?

Linux 下的函数库或提供编程接口的程序的软件包一般分两种,一种是运行时需要的,一种是编译时需要的(称为开发包,软件包名中一般包含”-dev”)。

例如,在 Debian 上,GNU C Library 就分为 libc6 和 libc6-dev 两个包,其中 libc6 提供了运行依赖 GNU C Library 的程序时需要的一些文件,如运行时需要的动态库;而libc6-dev 中则是一些编译依赖 GNU C Library 的程序时需要的一些文件,如编译时需要的头文件、链接时需要的库文件等等。

例如,要使用 PostgreSQL 数据库,则需要安装 postgresql-8.4,postgresql-client-8.4等包,但若要使用 PostgreSQL 提供的 API,则还需要安装 libecpg-dev 和/或 postgresql-server-dev-8.4。

另外,若在用 gcc 编译程序时 ld 报错说找不到 crt1.o,这说明需要安装 libc6-dev。

我明明已经包含了 foo.h, 怎么编译时还报 undefined reference to ‘foo’?

在 C 中,头文件一般提供声明,而 .c 文件用来提供实现,出现 undefined reference to 这种链接错误,说明没有提供头文件声明的函数的对应实现。可通过在链接时指定对应的库或者提供对应的 .c 文件(或其编译生成的 .o 文件)解决。

例如:

  • 包含了 math.h,使用 sin 等 math.h 中声明的函数时仍报 undefined reference to ‘sin’,需链接 libm 库,在调用 gcc 时加 -lm 参数。
  • 包含了 pthread.h,使用 pthread_create 等 pthread.h 中声明的函数时仍报 undefined reference to ‘pthread_create’, 需链接 libpthread,在调用 gcc 时加 -lpthread 参数。

想看下 Linux 下一些命令的源码,找不到

Linux 一下一些常见源码所属的包:
1) ls, cp 等命令在 coreutils 中,完整命令列表参见: http://www.gnu.org/software/coreutils/manual/coreutils.html
2) as, ld, readelf, objdump 等命令在 binutils 中,完整命令列表参见:http://www.gnu.org/software/binutils/

不同的Linux发行版和包管理系统上,官方所带的软件包数量和种类是有所区别的,如果在官方默认的安装源里找不到所需要的软件的源代码,可以Google之。

如何找到某个命令是属于哪个包的

这个和你使用的操作系统相关,对于 Linux,还和你使用的发行版及其包管理系统相关。例如在 Ubuntu 上,要查找 find 属于哪个包,可执行 dpkg -S /usr/bin/find, 从其返回的信息可知,find 属于 findutils。

有的时候,我们不知道系统上是否安装了某个软件包,这时,可以通过dpkg -s package_name来查看。例如,在我的Ubuntu 10.04上执行dpkg -s findutils的输出结果如下:

Package: findutils
Essential: yes
Status: install ok installed
Priority: required
Section: utils
Installed-Size: 1712
Maintainer: Ubuntu Developers
Architecture: i386
Version: 4.4.2-1ubuntu1
Pre-Depends: libc6 (>= 2.7)
Suggests: mlocate | locate | slocate
Description: utilities for finding files--find, xargs
 GNU findutils provides utilities to find files meeting specified
 criteria and perform various actions on the files which are found.
 This package contains 'find' and 'xargs'; however, 'locate' has
 been split off into a separate package.
Homepage: http://savannah.gnu.org/projects/findutils/
Original-Maintainer: Andreas Metzler 

Linux 如何支持大文件(单个文件大于2GB)的I/O操作?

在编译时使用 -D_FILE_OFFSET_BITS=64 (gcc) 定义 _FILE_OFFSET_BITS 宏为 64 即可。