导航:首页 > 源码编译 > 编译时加ldl

编译时加ldl

发布时间:2024-11-10 01:21:33

Ⅰ 程序报出bus err 错误后什么不能用backtrace没有输出内容

×

loading..

资讯
安全
论坛
下载
读书
程序开发
数据库
系统
网络
电子书
微信学院
站长学院
QQ
手机软件
考试

软件开发|
web前端|
Web开发|
移动开发|
综合编程|

首页 > 程序开发 > 软件开发 > C语言 > 正文

善用backtrace解决大问题

2011-07-22
0 个评论

收藏

我要投稿

一.用途:

主要用于程序异常退出时寻找错误原因

二.功能:

回溯堆栈,简单的说就是可以列出当前函数调用关系

三.原理:

1. 通过对当前堆栈的分析,找到其上层函数在栈中的帧地址,再分析上层函数的堆栈,再找再上层的帧地址……一直找到最顶层为止,帧地址指的是一块:在栈上存放局部变量,上层返回地址,及寄存器值的空间。

2.
由于不同处理器堆栈方式不同,此功能的具体实现是编译器的内建函数__buildin_frame_address及
__buildin_return_address中,它涉及工具glibc和gcc,
如果编译器不支持此函数,也可自己实现此函数,举例中有arm上的实现

四.方法:

在程序中加入backtrace及相关函数调用

五.举例:

1. 一般backtrace的实现

i. 程序

#include <signal.h>

#include <stdio.h>

#include <stdlib.h>

#include <execinfo.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <string.h>

#include <unistd.h>

#define PRINT_DEBUG

static void print_reason(int sig, siginfo_t * info, void *secret)

{

void *array[10];

size_t size;

#ifdef PRINT_DEBUG

char **strings;

size_t i;

size = backtrace(array, 10);

strings = backtrace_symbols(array, size);

printf("Obtained %zd stack frames.\n", size);

for (i = 0; i < size; i++)

printf("%s\n", strings[i]);

free(strings);

#else

int fd = open("err.log", O_CREAT | O_WRONLY);

size = backtrace(array, 10);

backtrace_symbols_fd(array, size, fd);

close(fd);

#endif

exit(0);

}

void die()

{

char *test1;

char *test2;

char *test3;

char *test4 = NULL;

strcpy(test4, "ab");

}

void test1()

{

die();

}

int main(int argc, char **argv)

{

struct sigaction myAction;

myAction.sa_sigaction = print_reason;

sigemptyset(&myAction.sa_mask);

myAction.sa_flags = SA_RESTART | SA_SIGINFO;

sigaction(SIGSEGV, &myAction, NULL);

sigaction(SIGUSR1, &myAction, NULL);

sigaction(SIGFPE, &myAction, NULL);

sigaction(SIGILL, &myAction, NULL);

sigaction(SIGBUS, &myAction, NULL);

sigaction(SIGABRT, &myAction, NULL);

sigaction(SIGSYS, &myAction, NULL);

test1();

}

ii. 编译参数

gcc main.c -o test -g -rdynamic

2. 根据不同的处理器自已实现backtrace

i. arm的backtrace函数实现

static int backtrace_xy(void **BUFFER, int SIZE)

{

volatile int n = 0;

volatile int *p;

volatile int *q;

volatile int ebp1;

volatile int eip1;

volatile int i = 0;

p = &n;

ebp1 = p[4];

eip1 = p[6];

fprintf(stderr, "======================= backtrace_xy addr: 0x%0x, param1: 0x%0x, param2: 0x%0x\n",

backtrace_xy, &BUFFER, &SIZE);

fprintf(stderr, "n addr is 0x%0x\n", &n);

fprintf(stderr, "p addr is 0x%0x\n", &p);

for (i = 0; i < SIZE; i++)

{

fprintf(stderr, "ebp1 is 0x%0x, eip1 is 0x%0x\n", ebp1, eip1);

BUFFER[i] = (void *)eip1;

p = (int*)ebp1;

q = p - 5;

eip1 = q[5];

ebp1 = q[2];

if (ebp1 == 0 || eip1 == 0)

break;

}

fprintf(stderr, "total level: %d\n", i);

return i;

}

六.举例2:

/*main.c*/

#include "sigsegv.h"

#include <string.h>

int die() {

char *err = NULL;

strcpy(err, "gonner");

return 0;

}

int main() {

return die();

}

/*sigsegv.c*/

#define _GNU_SOURCE

#include <memory.h>

#include <stdlib.h>

#include <stdio.h>

#include <signal.h>

#include <ucontext.h>

#include <dlfcn.h>

#include <execinfo.h>

#define NO_CPP_DEMANGLE

#ifndef NO_CPP_DEMANGLE

#include <cxxabi.h>

#endif

#if defined(REG_RIP)

# define SIGSEGV_STACK_IA64

# define REGFORMAT "%016lx"

#elif defined(REG_EIP)

# define SIGSEGV_STACK_X86

# define REGFORMAT "%08x"

#else

# define SIGSEGV_STACK_GENERIC

# define REGFORMAT "%x"

#endif

static void signal_segv(int signum, siginfo_t* info, void*ptr) {

static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"};

size_t i;

ucontext_t *ucontext = (ucontext_t*)ptr;

#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)

int f = 0;

Dl_info dlinfo;

void **bp = 0;

void *ip = 0;

#else

void *bt[20];

char **strings;

size_t sz;

#endif

fprintf(stderr, "Segmentation Fault!\n");

fprintf(stderr, "info->si_signo = %d\n", signum);

fprintf(stderr, "info->si_errno = %d\n", info->si_errno);

// fprintf(stderr, "info->si_code = %d (%s)\n", info->si_code, info->si_codes[si_code]);

fprintf(stderr, "info->si_addr = %p\n", info->si_addr);

for(i = 0; i < NGREG; i++)

fprintf(stderr, "reg[%02d] = 0x" REGFORMAT "\n", i, ucontext->uc_mcontext.gregs[i]);

#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)

# if defined(SIGSEGV_STACK_IA64)

ip = (void*)ucontext->uc_mcontext.gregs[REG_RIP];

bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP];

# elif defined(SIGSEGV_STACK_X86)

ip = (void*)ucontext->uc_mcontext.gregs[REG_EIP];

bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP];

# endif

fprintf(stderr, "Stack trace:\n");

while(bp != & ip) {

if(!dladdr(ip, &dlinfo))

break;

const char *symname = dlinfo.dli_sname;

#ifndef NO_CPP_DEMANGLE

int status;

char *tmp = __cxa_demangle(symname, NULL, 0, &status);

if(status == 0 !=& tmp)

symname = tmp;

#endif

fprintf(stderr, "% 2d: %p < %s+%u> (%s)\n",

++f,

ip,

symname,

(unsigned)(ip - dlinfo.dli_saddr),

dlinfo.dli_fname);

#ifndef NO_CPP_DEMANGLE

if(tmp)

free(tmp);

#endif

if(dlinfo.dli_sname != !strcmp(dlinfo.dli_sname, "main"))

break;

ip = bp[1];

bp = (void**)bp[0];

}

#else

fprintf(stderr, "Stack trace (non-dedicated):\n");

sz = backtrace(bt, 20);

strings = backtrace_symbols(bt, sz);

for(i = 0; i < sz; ++i)

fprintf(stderr, "%s\n", strings[i]);

#endif

fprintf(stderr, "End of stack trace\n");

exit (-1);

}

int setup_sigsegv() {

struct sigaction action;

memset(&action, 0, sizeof(action));

action.sa_sigaction = signal_segv;

action.sa_flags = SA_SIGINFO;

if(sigaction(SIGSEGV, &action, NULL) < 0) {

perror("sigaction");

return 0;

}

return 1;

}

#ifndef SIGSEGV_NO_AUTO_INIT

static void __attribute((constructor)) init(void)

{

setup_sigsegv();

}

#endif

/*sigsegv.h*/

#ifndef __sigsegv_h__

#define __sigsegv_h__

#ifdef __cplusplus

extern "C" {

#endif

int setup_sigsegv();

#ifdef __cplusplus

}

#endif

#endif /* __sigsegv_h__ */

编译时需要加入-rdynamic -ldl –ggdb

void

handle_signal_error(int rec_signal,siginfo_t* signal_info,void* context)

{

NE_Info* __attribute__ ((unused)) ne_info = NULL;

struct sigaction action;

FILE* file;

void* backtr[NUMBER_OF_BACKTRACE];

cpal_uns32 __attribute__ ((unused)) i = 0;

cpal_uns32 backtr_size = 0;

ucontext_t *u_context;

time_t seconds_time;

struct tm* time_struct;

cpal_si32 ret_t;

char filename[SIZE_OF_FILENAME];

if(g_handler_running)

return;

g_handler_running = CPAL_TRUE;

ret_t = time(&seconds_time);

if(ret_t != - 1)

{

time_struct = gmtime(&seconds_time);

snprintf(filename,SIZE_OF_FILENAME,"%s%d%d%d-%d%d%d-%s",BACKTRACE_FILE_PATH,time_struct->tm_mon,time_struct->tm_mday,

(time_struct->tm_year-100)+2000,time_struct->tm_hour,time_struct->tm_min,time_struct->tm_sec,BACKTRACE_FILE);

}

else

{

snprintf(filename,SIZE_OF_FILENAME,"%s",BACKTRACE_FILE);

}

file = fopen(filename,"w");

if(file == NULL)

{

return;

}

if(signal_info == NULL)

{

return;

}

if(context == NULL)

{

return;

}

u_context = (ucontext_t*)context;

/*Restore the default action for this signal and re-raise it, so that the default action occurs. */

action.sa_sigaction = SIG_DFL;

sigemptyset(&action.sa_mask);

action.sa_flags = SA_RESTART;

sigaction(rec_signal,&action,NULL);

/* Print out the backtrace. */

backtr_size = backtrace(backtr,20);

/* The backtrace points to sigaction in libc, not to where the signal was actually raised.

This overwrites the sigaction with where the signal was sent, so we can resolve the sender. */

#if __WORDSIZE == 64

backtr[1] = (void*)u_context->uc_mcontext.gregs[REG_RIP];

#else

backtr[1] = (void*)u_context->uc_mcontext.gregs[REG_EIP];

#endif //__WORDSIZE

backtrace_symbols_fd(backtr,backtr_size,fileno(file));

fprintf(file,"Backtrace is above.\nFatal signal %d received.\n",rec_signal);

#if __WORDSIZE == 64

fprintf(file,"Signal received at address %p from 0x%08x.\n",signal_info->si_addr,

u_context->uc_mcontext.gregs[REG_RIP]);

#else

fprintf(file,"Signal received at address %p from 0x%08x.\n",signal_info->si_addr,

u_context->uc_mcontext.gregs[REG_EIP]);

#endif //__WORDSIZE

#if CPAL_LM_DEBUG

/* Print all NE_Infos */

for(; i < MAX_NO_OF_CONNS; i++)

{

ne_info = g_ne_hash_tab[i];

while(ne_info != NULL)

{

ne_info = ne_info->next_ne;

}

}

#endif

fflush(file);

fclose(file);

sleep (50); /* Sleep for 50 seconds */

g_handler_running = *_FALSE;

raise(rec_signal);

}

Ⅱ gcc编译器究竟怎么打开我竟然在gcc的安装文件夹中找不到gcc的打开文件

你先用vim 或者直接用gedit编写好程序,然后直接输入命令就可以了,比如你的程序是helloworld.c,那么你可以输入命令:
编译命令:gcc -o helloworld helloworld.c
运行命令./helloworld

希望这样的回答对你有帮助!

gcc的使用方法

1。gcc包含的c/c++编译器
gcc,cc,c++,g++,gcc和cc是一样的,c++和g++是一样的,一般c程序就用gcc编译,c++程序就用g++编译

2。gcc的基本用法
gcc test.c这样将编译出一个名为a.out的程序
gcc test.c -o test这样将编译出一个名为test的程序,-o参数用来指定生成程序的名字

3。为什么会出现undefined reference to 'xxxxx'错误?
首先这是链接错误,不是编译错误,也就是说如果只有这个错误,说明你的程序源码本身没有问题,是你用编译器编译时参数用得不对,你没有指定链接程序要用到得库,比如你的程序里用到了一些数学函数,那么你就要在编译参数里指定程序要链接数学库,方法是在编译命令行里加入-lm。

4。-l参数和-L参数
-l参数就是用来指定程序要链接的库,-l参数紧接着就是库名,那么库名跟真正的库文件名有什么关系呢?
就拿数学库来说,他的库名是m,他的库文件名是libm.so,很容易看出,把库文件名的头lib和尾.so去掉就是库名了。

好了现在我们知道怎么得到库名了,比如我们自已要用到一个第三方提供的库名字叫libtest.so,那么我们只要把libtest.so拷贝到/usr/lib里,编译时加上-ltest参数,我们就能用上libtest.so库了(当然要用libtest.so库里的函数,我们还需要与libtest.so配套的头文件)。

放在/lib和/usr/lib和/usr/local/lib里的库直接用-l参数就能链接了,但如果库文件没放在这三个目录里,而是放在其他目录里,这时我们只用-l参数的话,链接还是会出错,出错信息大概是:"/usr/bin/ld: cannot find -lxxx",也就是链接程序ld在那3个目录里找不到libxxx.so,这时另外一个参数-L就派上用场了,比如常用的X11的库,它放在/usr/X11R6/lib目录下,我们编译时就要用-L/usr/X11R6/lib -lX11参数,-L参数跟着的是库文件所在的目录名。再比如我们把libtest.so放在/aaa/bbb/ccc目录下,那链接参数就是-L/aaa/bbb/ccc -ltest

另外,大部分libxxxx.so只是一个链接,以RH9为例,比如libm.so它链接到/lib/libm.so.x,/lib/libm.so.6又链接到/lib/libm-2.3.2.so,如果没有这样的链接,还是会出错,因为ld只会找libxxxx.so,所以如果你要用到xxxx库,而只有libxxxx.so.x或者libxxxx-x.x.x.so,做一个链接就可以了ln -s libxxxx-x.x.x.so libxxxx.so

手工来写链接参数总是很麻烦的,还好很多库开发包提供了生成链接参数的程序,名字一般叫xxxx-config,一般放在/usr/bin目录下,比如gtk1.2的链接参数生成程序是gtk-config,执行gtk-config --libs就能得到以下输出"-L/usr/lib -L/usr/X11R6/lib -lgtk -lgdk -rdynamic -lgmole -lglib -ldl -lXi -lXext -lX11 -lm",这就是编译一个gtk1.2程序所需的gtk链接参数,xxx-config除了--libs参数外还有一个参数是--cflags用来生成头文
件包含目录的,也就是-I参数,在下面我们将会讲到。你可以试试执行gtk-config --libs --cflags,看看输出结果。
现在的问题就是怎样用这些输出结果了,最苯的方法就是复制粘贴或者照抄,聪明的办法是在编译命令行里加入这个`xxxx-config --libs --cflags`,比如编译一个gtk程序:gcc gtktest.c `gtk-config --libs --cflags`这样就差
不多了。注意`不是单引号,而是1键左边那个键。

除了xxx-config以外,现在新的开发包一般都用pkg-config来生成链接参数,使用方法跟xxx-config类似,但xxx-config是针对特定的开发包,但pkg-config包含很多开发包的链接参数的生成,用pkg-config --list-all命令可以列出所支持的所有开发包,pkg-config的用法就是pkg-config pagName --libs --cflags,其中pagName是包名,是pkg-config--list-all里列出名单中的一个,比如gtk1.2的名字就是gtk+,pkg-config gtk+ --libs --cflags的作用跟gtk-config --libs --cflags是一样的。比如:gcc gtktest.c `pkg-config gtk+ --libs --cflags`。

5。-include和-I参数
-include用来包含头文件,但一般情况下包含头文件都在源码里用#include xxxxxx实现,-include参数很少用。-I参数是用来指定头文件目录,/usr/include目录一般是不用指定的,gcc知道去那里找,但是如果头文件不在/usr/include里我们就要用-I参数指定了,比如头文件放在/myinclude目录里,那编译命令行就要加上-I/myinclude参数了,如果不加你会得到一个"xxxx.h: No such file or directory"的错误。-I参数可以用相对路径,比如头文件在当前目录,可以用-I.来指定。上面我们提到的--cflags参数就是用来生成-I参数的。

6。-O参数
这是一个程序优化参数,一般用-O2就是,用来优化程序用的,比如gcc test.c -O2,优化得到的程序比没优化的要小,执行速度可能也有所提高(我没有测试过)。

7。-shared参数
编译动态库时要用到,比如gcc -shared test.c -o libtest.so

8。几个相关的环境变量
PKG_CONFIG_PATH:用来指定pkg-config用到的pc文件的路径,默认是/usr/lib/pkgconfig,pc文件是文本文件,扩展名是.pc,里面定义开发包的安装路径,Libs参数和Cflags参数等等。
CC:用来指定c编译器。
CXX:用来指定cxx编译器。
LIBS:跟上面的--libs作用差不多。
CFLAGS:跟上面的--cflags作用差不多。
CC,CXX,LIBS,CFLAGS手动编译时一般用不上,在做configure时有时用到,一般情况下不用管。
环境变量设定方法:export ENV_NAME=xxxxxxxxxxxxxxxxx

9。关于交叉编译
交叉编译通俗地讲就是在一种平台上编译出能运行在体系结构不同的另一种平台上,比如在我们地PC平台(X86 CPU)上编译出能运行在sparc CPU平台上的程序,编译得到的程序在X86 CPU平台上是不能运行的,必须放到sparc CPU平台上才能运行。
当然两个平台用的都是linux

这种方法在异平台移植和嵌入式开发时用得非常普遍。

相对与交叉编译,我们平常做的编译就叫本地编译,也就是在当前平台编译,编译得到的程序也是在本地执行。

用来编译这种程序的编译器就叫交叉编译器,相对来说,用来做本地编译的就叫本地编译器,一般用的都是gcc,但这种gcc跟本地的gcc编译器是不一样的,需要在编译gcc时用特定的configure参数才能得到支持交叉编译的gcc。

为了不跟本地编译器混淆,交叉编译器的名字一般都有前缀,比如sparc-xxxx-linux-gnu-gcc,sparc-xxxx-linux-gnu-g++ 等等

10。交叉编译器的使用方法
使用方法跟本地的gcc差不多,但有一点特殊的是:必须用-L和-I参数指定编译器用sparc系统的库和头文件,不能用本地(X86)
的库(头文件有时可以用本地的)。
例子:
sparc-xxxx-linux-gnu-gcc test.c -L/path/to/sparcLib -I/path/to/sparcInclude

Ⅲ 请教Linux下ALSA声道切换

解各参数含义及些基本概念
本度(sample):本记录音频数据基本单位见8位16位
通道数(channel):该参数1表示单声道2则立体声
桢(frame):桢记录声音单元其度本度与通道数乘积
采率(rate):每秒钟采数该数针桢言
周期(period):音频设备处理所需要桢数于音频设备数据访问及音频数据存储都单位
交错模式(interleaved):种音频数据记录式交错模式数据连续桢形式存放即首先记录完桢1左声道本右声道本(假设立体声格式)再始桢2记录非交错模式首先记录周期内所桢左声道本再记录右声道本数据连续通道式存储数情况我需要使用交错模式

period(周期):硬件断间间隔间表示输入延
声卡接口指针指示声卡硬件缓存区前读写位置要接口运行指针循环指向缓存区某位置
frame size = sizeof(one sample) * nChannels
alsa配置缓存(buffer)周期(size)runtime帧(frames)形式存储
period_bytes = frames_to_bytes(runtime, runtime->period_size);
bytes_to_frames()

The period and buffer sizes are not dependent on the sample format because they are measured in frames; you do not need to change them.

ALSA声音编程介绍
ALSA表示高级Linux声音体系结构(Advanced Linux Sound Architecture)由系列内核驱应用程序编译接口(API)及支持Linux声音实用程序组篇文章我简单介绍ALSA项目基本框架及软件组主要集介绍PCM接口编程包括您自实践程序示例

您使用ALSA原能新并唯用声音API您想完低级声音操作便能够化控制声音并化提高性能或者您使用其声音API没特性ALSA选择您已经写音频程序能想要ALSA声卡驱添加本支持您音频兴趣想播放音频文件高级API更选择比SDL,OpenAL及些桌面环境提供工具集另外您能ALSA支持Linux环境使用ALSA

ALSA历史
ALSA项目发起起Linux声卡驱(OSS/Free drivers)没积极维护并且落于新声卡技术Jaroslav Kysela早先写声卡驱并由始ALSA项目随便更发者加入发队伍更声卡支持API结构重组

Linux内核2.5发程ALSA合并官源码树发布内核2.6ALSA已经内建稳定内核版本并广泛使用

数字音频基础
声音由变化气压组麦克风转换器转换电形式模/数(ADC)转换器模拟电压转换离散本值声音固定间间隔采采速率称采率本输数/模(DAC)转换器比扩音器转换原模拟信号
本位表示本影响声音转换数字信号精确程度素另主要素采率奈奎斯特(Nyquist)理论要离散系统奈奎斯特频率高于采信号高频率或带宽避免混叠现象

ALSA基础
ALSA由许声卡声卡驱程序组同提供称libasoundAPI库应用程序发者应该使用libasound内核ALSA接口libasound提供高级并且编程便编程接口并且提供设备逻辑命名功能发者甚至需要知道类似设备文件低层接口相反OSS/Free驱内核系统调用级编程要求发者提供设备文件名并且利用ioctrl实现相应功能向兼容ALSA提供内核模块模拟OSS前许OSS基础发应用程序需要任何改ALSA运行另外libaoss库模拟OSS需要内核模块
ALSA包含插件功能使用插件扩展新声卡驱包括完全用软件实现虚拟声卡ALSA提供系列基于命令行工具集比混音器(mixer)音频文件播放器(aplay)及控制特定声卡特定属性工具

ALSA体系结构
ALSA API解几主要接口:
1 控制接口:提供管理声卡注册请求用设备通用功能
2 PCM接口:管理数字音频放(playback)录音(capture)接口本文续总结重点放接口发数字音频程序用接口
3 Raw MIDI接口:支持MIDI(Musical Instrument Digital Interface),标准电乐器些API提供声卡MIDI总线访问原始接口基于MIDI事件工作由程序员负责管理协议及间处理
4 定器(Timer)接口:同步音频事件提供声卡间处理硬件访问
5 序器(Sequencer)接口
6 混音器(Mixer)接口

设备命名
API库使用逻辑设备名设备文件设备名字真实硬件名字插件名字硬件名字使用hw:i,j格式其i卡号j块声卡设备号第声音设备hw:0,0.别名默认引用第块声音设备并且本文示例真用插件使用另外唯名字比plughw:,表示插件插件提供硬件设备访问提供像采率转换软件特性硬件本身并支持特性

声音缓存数据传输
每声卡都硬件缓存区保存记录本缓存区足够满声卡产断内核声卡驱使用直接内存(DMA)访问通道本传送内存应用程序缓存区类似于放任何应用程序使用DMA自缓存区数据传送声卡硬件缓存区
硬件缓存区环缓存说数据达缓存区末尾重新缓存区起始位置ALSA维护指针指向硬件缓存及应用程序缓存区数据操作前位置内核外部看我应用程序缓存区兴趣所本文讨论应用程序缓存区

应用程序缓存区通ALSA库函数调用控制缓存区传输操作能导致接受延迟我称延(latency)解决问题ALSA缓存区拆系列周期(period)(OSS/Free叫片断fragments).ALSAperiod单元传送数据
周期(period)存储些帧(frames)每帧包含间点所抓取本于立体声设备帧包含两信道本图1展示解程:缓存区解周期帧本图包含些假定数值图左右信道信息交替存储帧内称交错(interleaved)模式非交错模式信道所本数据存储另外信道数据

Over and Under Run
声卡数据总连续硬件缓存区应用程序缓存区间传输例外录音例应用程序读取数据够快循环缓存区新数据覆盖种数据丢失称overrun.放例应用程序写入数据缓存区速度够快缓存区"饿死"错误称"underrun"ALSA文档两种情形统称"XRUN"适设计应用程序化XRUN并且恢复

典型声音程序
使用PCM程序通类似面伪代码:
打放或录音接口
设置硬件参数(访问模式数据格式信道数采率等等)
while 数据要处理:
读PCM数据(录音)
或 写PCM数据(放)
关闭接口

我文看些工作代码我建议您Linux系统测试运行些代码查看输并尝试修改推荐代码本文相关所实例清单FTP获取:ftp.ssc.com/pub/lj/listings/issue126/6735.tgz

Listing 1. Display Some PCM Types and Formats

#include asoundlib.h>

int main() {
int val;

printf("ALSA library version: %s/n",
SND_LIB_VERSION_STR);

printf("/nPCM stream types:/n");
for (val = 0; val <= SND_PCM_STREAM_LAST; val++)
printf(" %s/n",
snd_pcm_stream_name((snd_pcm_stream_t)val));

printf("/nPCM access types:/n");
for (val = 0; val <= SND_PCM_ACCESS_LAST; val++)
printf(" %s/n",
snd_pcm_access_name((snd_pcm_access_t)val));

printf("/nPCM formats:/n");
for (val = 0; val <= SND_PCM_FORMAT_LAST; val++)
if (snd_pcm_format_name((snd_pcm_format_t)val)
!= NULL)
printf(" %s (%s)/n",
snd_pcm_format_name((snd_pcm_format_t)val),
snd_pcm_format_description(
(snd_pcm_format_t)val));

printf("/nPCM subformats:/n");
for (val = 0; val <= SND_PCM_SUBFORMAT_LAST;
val++)
printf(" %s (%s)/n",
snd_pcm_subformat_name((
snd_pcm_subformat_t)val),
snd_pcm_subformat_description((
snd_pcm_subformat_t)val));

printf("/nPCM states:/n");
for (val = 0; val <= SND_PCM_STATE_LAST; val++)
printf(" %s/n",
snd_pcm_state_name((snd_pcm_state_t)val));

return 0;
}
清单显示些ALSA使用PCM数据类型参数首先需要做包括文件些文件包含所库函数声明其显示ALSA库版本
程序剩部迭代些PCM数据类型流类型始ALSA每迭代值提供符号量名并且提供功能函数显示某特定值描述字符串看ALSA支持许格式我1.0.15版本支持达36种格式
程序必须链接alsalib库通编译需要加-lasound选项些alsa库函数使用dlopen函数及浮点操作所您能需要加-ldl,-lm选项
面该程序Makefile:
CC=gcc
TARGET=test
SRC=$(wildcard *.c)

OBJECT= ${SRC:.c=.o}
INCLUDES=-I/usr/include/alsa
LDFLAGS=-lasound

all:$(TARGET)

$(OBJECT):$(SRC)
$(CC) -c $(INCLUDES) $<

$(TARGET):$(OBJECT)
$(CC) -o $@ $< $(LDFLAGS)

.PHONY:clean

clean:
@rm -rf $(OBJECT) $(TARGET) *~

Listing 2. Opening PCM Device and Setting Parameters

/*

This example opens the default PCM device, sets
some parameters, and then displays the value
of most of the hardware parameters. It does not
perform any sound playback or recording.

*/

/* Use the newer ALSA API */
#define ALSA_PCM_NEW_HW_PARAMS_API

/* All of the ALSA library API is defined
* in this header */
#include asoundlib.h>

int main() {
int rc;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int val, val2;
int dir;
snd_pcm_uframes_t frames;

/* Open PCM device for playback. */
rc = snd_pcm_open(&handle, "default",
SND_PCM_STREAM_PLAYBACK, 0);
if (rc < 0) {
fprintf(stderr,
"unable to open pcm device: %s/n",
snd_strerror(rc));
exit(1);
}

/* Allocate a hardware parameters object. */
snd_pcm_hw_params_alloca(?ms);

/* Fill it in with default values. */
snd_pcm_hw_params_any(handle, params);

/* Set the desired hardware parameters. */

/* Interleaved mode */
snd_pcm_hw_params_set_access(handle, params,
SND_PCM_ACCESS_RW_INTERLEAVED);

/* Signed 16-bit little-endian format */
snd_pcm_hw_params_set_format(handle, params,
SND_PCM_FORMAT_S16_LE);

/* Two channels (stereo) */
snd_pcm_hw_params_set_channels(handle, params, 2);

/* 44100 bits/second sampling rate (CD quality) */
val = 44100;
snd_pcm_hw_params_set_rate_near(handle,
params, &val, &dir);

/* Write the parameters to the driver */
rc = snd_pcm_hw_params(handle, params);
if (rc < 0) {
fprintf(stderr,
"unable to set hw parameters: %s/n",
snd_strerror(rc));
exit(1);
}

/* Display information about the PCM interface */

printf("PCM handle name = '%s'/n",
snd_pcm_name(handle));

printf("PCM state = %s/n",
snd_pcm_state_name(snd_pcm_state(handle)));

snd_pcm_hw_params_get_access(params,
(snd_pcm_access_t *) &val);
printf("access type = %s/n",
snd_pcm_access_name((snd_pcm_access_t)val));

snd_pcm_hw_params_get_format(params, &val);
printf("format = '%s' (%s)/n",
snd_pcm_format_name((snd_pcm_format_t)val),
snd_pcm_format_description(
(snd_pcm_format_t)val));

snd_pcm_hw_params_get_subformat(params,
(snd_pcm_subformat_t *)&val);
printf("subformat = '%s' (%s)/n",
snd_pcm_subformat_name((snd_pcm_subformat_t)val),
snd_pcm_subformat_description(
(snd_pcm_subformat_t)val));

snd_pcm_hw_params_get_channels(params, &val);
printf("channels = %d/n", val);

snd_pcm_hw_params_get_rate(params, &val, &dir);
printf("rate = %d bps/n", val);

snd_pcm_hw_params_get_period_time(params,
&val, &dir);
printf("period time = %d us/n", val);

snd_pcm_hw_params_get_period_size(params,
&frames, &dir);
printf("period size = %d frames/n", (int)frames);

snd_pcm_hw_params_get_buffer_time(params,
&val, &dir);
printf("buffer time = %d us/n", val);

snd_pcm_hw_params_get_buffer_size(params,
(snd_pcm_uframes_t *) &val);
printf("buffer size = %d frames/n", val);

snd_pcm_hw_params_get_periods(params, &val, &dir);
printf("periods per buffer = %d frames/n", val);

snd_pcm_hw_params_get_rate_numden(params,
&val, &val2);
printf("exact rate = %d/%d bps/n", val, val2);

val = snd_pcm_hw_params_get_sbits(params);
printf("significant bits = %d/n", val);

snd_pcm_hw_params_get_tick_time(params,
&val, &dir);
printf("tick time = %d us/n", val);

val = snd_pcm_hw_params_is_batch(params);
printf("is batch = %d/n", val);

val = snd_pcm_hw_params_is_block_transfer(params);
printf("is block transfer = %d/n", val);

val = snd_pcm_hw_params_is_double(params);
printf("is double = %d/n", val);

val = snd_pcm_hw_params_is_half_plex(params);
printf("is half plex = %d/n", val);

val = snd_pcm_hw_params_is_joint_plex(params);
printf("is joint plex = %d/n", val);

val = snd_pcm_hw_params_can_overrange(params);
printf("can overrange = %d/n", val);

val = snd_pcm_hw_params_can_mmap_sample_resolution(params);
printf("can mmap = %d/n", val);

val = snd_pcm_hw_params_can_pause(params);
printf("can pause = %d/n", val);

val = snd_pcm_hw_params_can_resume(params);
printf("can resume = %d/n", val);

val = snd_pcm_hw_params_can_sync_start(params);
printf("can sync start = %d/n", val);

snd_pcm_close(handle);

return 0;
}

Ⅳ 交叉编译时提示 对'__C_ctype_b'的未定义引用

出现这种情况的原因,主要是C/C++编译为obj文件的时候并不旅卖需要函数的具体实现,只要有函数的原型即可。但是在链接为可执行文件的时候就必须要具体的实现了。如果错误是未声明的引用,那就是找不到函数的原型,解决办法这里就不细致说了,通常是相关的头文件未包含。
解决办法
指定原因就好办了,既然知道是缺少了函数的喊昌具体实现,那么就给它这个函数的实现就好了。比如上面的例子,是因为缺失了dlopen、dlsym、dlerror、dlclose这些函数的实现,这几个函数是用于加载动态链接库的,编译的时候需要添加-ldl来使用dl库(这是静态库,在系统目录下/usr/lib/i386-linux-gnu/libdl.a、/usr/lib/x86_64-linux-gnu/libdl.a)。
但是看上面编译的时候是有添加-ldl选项的,那么为什么不行呢?
gcc 依赖顺序问题
这个主要的原因是gcc编译的时候,各个文件依赖顺序的问题。
在gcc编译的时候,如果文件a依赖于文件b,那么编译的时候必须把a放前面,b放后面。
例如:在main.c中使用了pthread库相关函数,那么编译的时候必须是main.c在前,-lpthread在后。gcc main.c -lpthread -o a.out。
上面拆渗逗出现问题的原因就是引入库的顺序在前面了,将其放置在后面即可了。
g++ -o spider bloomfilter.o confparser.o crc32.o dso.o hashs.o md5.o qstring.o sha1.o socket.o spider.o threads.o url.o -rdynamic -lpthread -levent -lcrypt -ldl

阅读全文

与编译时加ldl相关的资料

热点内容
在哪里看每个app用了多长时间 浏览:635
学程序员要英语四级吗 浏览:131
java视频录制 浏览:756
口头指派式命令 浏览:470
php开发工程师面试题 浏览:954
linux内核源码pdf 浏览:66
mc命令方块怎么提取 浏览:367
有关程序员的五大魔咒你中了几个 浏览:204
本地文件如何上传linux服务器 浏览:17
传奇资源网站源码 浏览:377
f26app怎么下载 浏览:120
程序员与酒 浏览:439
php政府网站源码 浏览:912
前端面试常问算法 浏览:153
pythonopen可以打开文件夹吗 浏览:635
不锈钢加密网带厂家 浏览:347
哪一年除夕不算法定节假日 浏览:40
程序员对键盘的需求 浏览:605
程序员的峥嵘岁月 浏览:58
python调用类里面的函数 浏览:473