- 浏览: 214350 次
- 来自: 北京
文章分类
Linux应用程序开发
整理:Jims of 肥肥世家
Copyright © 2006 本文遵从GNU 的自由文档许可证(Free Documentation License)的条款,欢迎转载、修改、散布。
发布时间:2006年11月01日
Abstract
我的Linux应用程序开发笔记,从这里开始我的Linux开发之旅。
Table of Contents
Linux是使用C语言开发的,基于Linux平台的应用程序开发,C语言是首选的开发语言。本章记录C语言的基本概念/ 和基础知识。
在设置Linux的系统路径时,使用冒号分隔每个路径名。如:
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/bin/X11"
在Linux中的程序有两种,一种是可执行程序,与Windows下的.exe文件类似,一种是脚本,与Windows下的.bat文件类似。
Linux中常用的程序存放路径有以下几个:
/bin,该路径存放系统启动时需要使用的程序。
/usr/bin,该路径存放用户需使用的标准程序。
/usr/local/bin,该路径存放本地安装的程序。
Linux使用斜杠"/"分隔路径名,而不是Windows的反斜杠"/"。
Linux下的C编译器使用GCC,由于历史的原因,在POSIX兼容的操作系统中,C编译器都叫cc,所以Linux下也 有一个cc命令,它是一个到gcc的软链接。
开发工具,多数位于/usr/bin或/usr/local/bin目录下。
头文件,位于/usr/include目录。头文件包含有常量定义、系统调用和库函数调用的声明。这是系统默认的头文 件存放路径,在编译程序时,编译器会自动查找该目录。gcc编译器在编译程序时也可用-I参数指定另外的头文件路径。如:
gcc -I/usr/local/myinclude test.c。
库文件,库是一组已编译的函数集合,可方便我们重用代码。默认存放在/lib和/usr/lib目录。库文件可分为静 态和共享两类。
.a,静态库文件。使用静态库将会把所有的库代码引入程序,占用更多的磁盘空间和内存空间,所以一般建议使用共享库。
.so,共享库文件。使用共享库的程序不包含库代码,只在程序运行才调用共享库中的代码。
在编译时可用包含路径的库文件名或用-l参数指定使用的库文件,/usr/lib/libm.a等价于-lm。如:
gcc -o hello hello.c /usr/lib/libm.a
或用-l参数写成
gcc -o hello hello.c -lm
如果我们要使用的库文件不在默认位置,在编译程序时可用-L参数指定库文件的路径。下面例子使用了/usr/hello/lib目录下的libhello库文件:
gcc -o hello -L/usr/hello/lib hello.c -lhello
创建和使用静态库。
-
分别创建两个函数,函数a的内容如下:
#include <stdio.h>
void a(char *arg)
{
printf("function a,hello world %s/n",arg);
}函数b的内容如下:
#include <stdio.h>
void b(int arg)
{
printf("function b,hello world %d/n",arg);
} -
接着,生成两个对象文件。
debian:~/c# gcc -c a.c b.c
debian:~/c# ls *.o
a.o b.o -
最后,用ar归档命令把生成的对象文件打包成一个静态库libhello.a。
debian:~/c# ar crv libhello.a a.o b.o
r - a.o
r - b.o -
为我们的静态库定义一个头文件lib.h,包含这两个函数的定义。
/*
* this is a header file.
*/
void a(char *arg);
void b(int arg);
}}}
* 创建jims.c程序,内容如下。{{{#!cplusplus
#include "lib.h"
int main()
{
a("jims.yang");
b(3);
exit(0);
} -
利用静态链接库编译程序。
debian:~/c# gcc -c jims.c
debian:~/c# gcc -o jims jims.o libhello.a
debian:~/c# ./jims
function a,hello world jims.yang
function b,hello world 3
debian:~/c#
gcc -o jims jims.o libhello.a也可以写成gcc -o jims jims.o -L. -lhello。
预处理,在程序开头以“#”开头的命令就是预处理命令,它在语法扫描和分析法时被预处理程序处理。预处理有以下几类:
-
宏定义,用#define指令定义。如:#define BUFFER 1024。取消宏定义用#undef指令。宏还可带参数,如:
#define BUF(x) x*3
-
包含头文件,用#include指令,可把包含的文件代码插入当前位置。如:
<#include <stdio.h>。
包含的文件可以用尖括号,也可用双引号,如:
#include "stdio.h"。
不同之处是,使用尖括号表示在系统的包含目录(/usr/include)下查找该文件,而双引号表示在当前目录下查找包含文件。每行只能包含一个包含文件,要包含多个文件要用多个#include指令。
-
条件编译,格式如下:
格式一,如果定义了标识符,则编译程序段1,否则编译程序段2:
#ifdef 标识符
程序段1
#else
程序段2
#endif
格式二,如果定义了标识符,则编译程序段2,否则编译程序段1,与格式一相反:
#ifndef 标识符
程序段1
#else
程序段2
#endif
格式三,常量表达式为真则编译程序段1,否则编译程序段2:
#if 常量表达式
程序段1
#else
程序段2
#endif
使用gcc编译程序时,要经过四个步骤。
-
预处理(Pre-Processing),用-E参数可以生成预处理后的文件。
debian:~/c# gcc -E hello.c -o hello.i
编译(Compiling)
汇编(Assembling)
链接(Linking)
GCC默认将.i文件看成是预处理后的C语言源代码,所以我们可以这样把.i文件编译成目标文件。
debian:~# gcc -c hello.i -o hello.o}}}
在GCC中使用-pedantic选项能够帮助程序员发现一些不符合ANSI/ISO C标准的代码,但不是全部。从程序员的角度看,函数库实际上就是一些头文件(.h)和库文件(.so或者.a)的集合。
在Linux系统内所有东西都是以文件的形式来表示的,除一般的磁盘文件外,还有设备文件,如硬盘、声卡、串口、打印机等。设备文件又可分为字符设备文件(character devices)和块设备文件(block devices)。使用man hier命令 可以查看Linux文件系统的分层结构。文件的处理方法一般有五种,分别是:
open,打开一个文件或设备。
close,关闭一个打开的文件或设备。
read,从一个打开的文件或者设备中读取信息。
write,写入一个文件或设备。
ioctl,把控制信息传递给设备驱动程序。
open, close,read,write和ioctl都是低级,没有缓冲的文件操作函数,在实际程序开发中较少使用,一般我们使用标准I/O函数库来处理文件操 作。如:fopen,fclose,fread,fwrite,fflush等。在使用标准I/O库时,需用到stdio.h头文件。
一些常用的文件和目录维护函数:chmod、chown、unlink、link、symlink、mkdir、rmdir、chdir、getcwd、opendir,closedir、readdir、telldir、seekdir等。
fcntl用于维护文件描述符,mmap用于分享内存。
创建文档并输入信息的示例代码:
#include <stdio.h>
main(void)
{
FILE *fp1;
char c;
fp1 = fopen("text.txt","w");
while ((c = getchar())!= '/n')
putc(c,fp1);
fclose(fp1);
}
显示路径的示例代码
#include <unistd.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *topdir = ".";
if (argc >= 2)
topdir = argv[1];
printf("Directory scan of %s/n", topdir);
printdir(topdir,0);
printf("done./n");
exit(0);
}
printdir(char *dir, int depth)
{
DIR *dp;
struct dirent *entry;
struct stat statbuf;
if((dp = opendir(dir)) == NULL)
{
fprintf(stderr,"cannot open directory:%s/n",dir);
return;
}
chdir(dir);
while((entry = readdir(dp)) != NULL)
{
lstat(entry->d_name,&statbuf);
if(S_ISDIR(statbuf.st_mode))
{
if(strcmp(".",entry->d_name) == 0 || strcmp("..",entry->d_name) == 0)
continue;
printf("%*s%s//n",depth,"",entry->d_name);
printdir(entry->d_name,depth+4);
}
else printf("%*s%s/n",depth,"",entry->d_name);
}
chdir("..");
closedir(dp);
}
void main()表示程序没有参数,int main(int argc, char *argv[])表示程序要带参数,argc保存着参数的个数,argv[]数组保存着参数列表。如:
debian:~# mytest a b c
argc: 4
argv: ["mytest","a","b","c"]
getopt()函数和getopt_long()用来处理程序选项。getopt_long()函数可以处理以"--"开头的选项。Gnu官方手册页:http://www.gnu.org/software/libc/manual/html_node/Getopt.html
获取命令行参数的示例代码:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int opt;
while((opt = getopt(argc,argv,"if:lr")) != -1) /* 返回“-1”表示已没选项需要处理。*/
{
switch(opt){
case 'i':
case 'l':
case 'r':
printf("option: %c/n", opt);
break;
case 'f':
printf("filename: %s/n", optarg); /*如果选项需要一个参数,则参数存放在外部变量optarg中。*/
break;
case ':':
printf("option needs a value /n"); /*“:”表示选项需要参数*/
break;
case '?':
printf("unknown option: %c/n", optopt); /*返回“?”表示无效的选项,并把无效的选项存放在外部变量optopt中。*/
break;
}
}
for(; optind < argc; optind++) /*外部变量optind指向下一个要处理的选项索引值。*/
printf("argument: %s/n", argv[optind]);
}
在bash shell中使用set命令可以列出Linux系统的环境变量,在C程序中我们也可以用putenv()和getenv()函数来获取Linux系统的环境变量。这两个函数的声明如下:
char *getenv(const char *name);
int putenv(const char *string);
系统有一个environ变量记录了所有的系统变量。下面的示例代码可把environ的值显示同来。
#include <stdlib.h>
#include <stdio.h>
extern char **environ;
int main()
{
char **env = environ;
while(*env)
{
printf("%s/n",*env);
env++;
}
}
linux和其它unix一样,使用GMT1970年1月1日子夜作为系统时间的开始,也叫UNIX纪元的开始。现在的时间表示为UNIX纪元至今经过的秒数。
#include <time.h>
time_t time(time_t *t);
显示系统时间的示例代码:
#include <time.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
int i;
time_t the_time;
for(i = 1; i <= 10; i++){
the_time = time((time_t *)0);
printf("%d the time is %ld/n", i, the_time);
sleep(2);
}
}
用ctime()函数以友好方式返回当前时间,它的函数声明格式:
#include <time.h>
char *ctime(const time_t *timeval);
示例:
#include <time.h>
#include <stdio.h>
int main(void)
{
time_t time1;
(void)time(&time1);
printf("The date is: %s/n",ctime(&time1));
}
用mkstemp()函数创建临时文件。声明:
#include<stdlib.h>
int mkstemp(char * template);
示例:
#include <stdio.h>
int main(void)
{
char template[] = "template-XXXXXX";
int fp;
fp = mkstemp(template);
printf("template = %s/n", template);
close(fp);
}
获取用户信息。
声明:
#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwuid(uid_t uid); /* 根据uid返回用户信息 */
struct passwd *getpwnam(const char *name); /* 根据用户名返回用户信息 */
passwd结构体说明:
passwd Member Description
char *pw_name The user's login name
uid_t pw_uid The UID number
gid_t pw_gid The GID number
char *pw_dir The user's home directory
char *pw_gecos The user's full name
char *pw_shell The user's default shell
示例代码:
#include <stdio.h>
#include <sys/types.h>
#include <stdio.h>
#include <pwd.h>
int main(void)
{
uid_t uid;
gid_t gid;
struct passwd *pw;
uid = getuid();
gid = getgid();
pw = getpwuid(uid);
printf("User is %s/n", getlogin());
printf("The uid is:%d/n", uid);
printf("The gid is:%d/n",gid);
printf("The pw struct:/n name=%s, uid=%d, gid=%d, home=%s,shell=%s/n", pw->pw_name, pw->pw_uid, pw->pw_gid, pw->pw_dir, pw->pw_shell);
}
用gethostname()函数获取主机名。
函数声明:
#include <unistd.h>
int gethostname(char *name, size_t namelen); /* 主机名返回给name变量 */
示例代码:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
char computer[100];
int status;
status = gethostname(computer, 100);
printf("The status is %d/n", status);
printf("The hostname is: %s/n", computer);
}
用uname()函数获取主机详细信息,就像shell的uname命令返回的信息一样。
函数声明:
#include <sys/utsname.h>
int uname(struct utsname *name);
utsname结构体说明:
utsname Member Description
char sysname[] The operating system name
char nodename[] The host name
char release[] The release level of the system
char version[] The version number of the system
char machine[] The hardware type
示例代码:
#include <stdio.h>
#include <unistd.h>
#include <sys/utsname.h>
int main(void)
{
char computer[100];
int status;
struct utsname uts;
status = gethostname(computer,100);
printf("The computer's size is %d/n",sizeof(computer));
printf("The status is %d/n", status);
printf("The hostname is: %s/n", computer);
uname(&uts);
printf("The uname's information./n uts.sysname=%s/n uts.machine=%s/n uts.nodename=%s/n uts.release=%s/n uts.version=%s/n", uts.sysname,uts.machine,uts.nodename,uts.release,uts.version);
}
使用syslog()函数处理日志信息。
函数声明:
#include <syslog.h>
void syslog(int priority, const char *message, arguments...);
priority参数的格式(severity level|facility code)
示例:
LOG_ERR|LOG_USER
severity level:
Priority Level Description
LOG_EMERG An emergency situation
LOG_ALERT High-priority problem, such as database corruption
LOG_CRIT Critical error, such as hardware failure
LOG_ERR Errors
LOG_WARNING Warning
LOG_NOTICE Special conditions requiring attention
LOG_INFO Informational messages
LOG_DEBUG Debug messages
facility value(转自syslog.h头文件):
/* facility codes */
#define LOG_KERN (0<<3) /* kernel messages */
#define LOG_USER (1<<3) /* random user-level messages */
#define LOG_MAIL (2<<3) /* mail system */
#define LOG_DAEMON (3<<3) /* system daemons */
#define LOG_AUTH (4<<3) /* security/authorization messages */
#define LOG_SYSLOG (5<<3) /* messages generated internally by syslogd */
#define LOG_LPR (6<<3) /* line printer subsystem */
#define LOG_NEWS (7<<3) /* network news subsystem */
#define LOG_UUCP (8<<3) /* UUCP subsystem */
#define LOG_CRON (9<<3) /* clock daemon */
#define LOG_AUTHPRIV (10<<3) /* security/authorization messages (private) */
#define LOG_FTP (11<<3) /* ftp daemon */
示例代码:
#include <syslog.h>
#include <stdio.h>
int main(void)
{
FILE *f;
f = fopen("abc","r");
if(!f)
syslog(LOG_ERR|LOG_USER,"test - %m/n");
}
上面的日志信息由系统自动给出,我们也可过滤日志信息。用到以下函数:
#include <syslog.h>
void closelog(void);
void openlog(const char *ident, int logopt, int facility);
int setlogmask(int maskpri);
logopt参数的选项:
logopt Parameter Description
LOG_PID Includes the process identifier, a unique number allocated to each process by the system, in the messages.
LOG_CONS Sends messages to the console if they can’t be logged.
LOG_ODELAY Opens the log facility at first call to .
LOG_NDELAY Opens the log facility immediately, rather than at first log.
示例代码:
#include <syslog.h>
#include <stdio.h>
#include <unistd.h>
int main(void)
{
int logmask;
openlog("logmask", LOG_PID|LOG_CONS, LOG_USER); /*日志信息会包含进程id。*/
syslog(LOG_INFO, "informative message, pid=%d", getpid());
syslog(LOG_DEBUG,"debug message, should appear"); /*记录该日志信息。*/
logmask = setlogmask(LOG_UPTO(LOG_NOTICE)); /*设置屏蔽低于NOTICE级别的日志信息。*/
syslog(LOG_DEBUG, "debug message, should not appear"); /*该日志信息被屏蔽,不记录。*/
}
不同安全级别的日志信息存放在/var/log目录下的哪个文件中是由/etc/syslog.conf文件控制的,下面是我系统中syslog.conf文件的内容:
# /etc/syslog.conf Configuration file for syslogd.
#
# For more information see syslog.conf(5)
# manpage.
#
# First some standard logfiles. Log by facility.
#
auth,authpriv.* /var/log/auth.log
*.*;auth,authpriv.none -/var/log/syslog
#cron.* /var/log/cron.log
daemon.* -/var/log/daemon.log
kern.* -/var/log/kern.log
lpr.* -/var/log/lpr.log
mail.* -/var/log/mail.log
user.* -/var/log/user.log
uucp.* /var/log/uucp.log
#
# Logging for the mail system. Split it up so that
# it is easy to write scripts to parse these files.
#
mail.info -/var/log/mail.info
mail.warn -/var/log/mail.warn
mail.err /var/log/mail.err
# Logging for INN news system
#
news.crit /var/log/news/news.crit
news.err /var/log/news/news.err
news.notice -/var/log/news/news.notice
#
# Some `catch-all' logfiles.
#
*.=debug;/
auth,authpriv.none;/
news.none;mail.none -/var/log/debug
*.=info;*.=notice;*.=warn;/
auth,authpriv.none;/
cron,daemon.none;/
mail,news.none -/var/log/messages
#
# Emergencies are sent to everybody logged in.
#
*.emerg *
#
# I like to have messages displayed on the console, but only on a virtual
# console I usually leave idle.
#
#daemon,mail.*;/
# news.=crit;news.=err;news.=notice;/
# *.=debug;*.=info;/
# *.=notice;*.=warn /dev/tty8
# The named pipe /dev/xconsole is for the `xconsole' utility. To use it,
# you must invoke `xconsole' with the `-file' option:
#
# $ xconsole -file /dev/xconsole [...]
#
# NOTE: adjust the list below, or you'll go crazy if you have a reasonably
# busy site..
#
daemon.*;mail.*;/
news.crit;news.err;news.notice;/
*.=debug;*.=info;/
*.=notice;*.=warn |/dev/xconsole
相关推荐
《Linux应用程序开发详解》这本书是为初学者量身打造的一份全面而详尽的Linux开发指南。它旨在帮助读者从零开始,逐步掌握在Linux环境下进行应用程序开发的各种技术和工具。书中的内容涵盖了从基础的Linux操作系统...
嵌入式Linux应用程序开发是IT领域中的一个重要分支,它涉及到硬件、操作系统以及软件设计等多个方面。本教程聚焦于如何在嵌入式系统中利用Linux进行高效的应用程序开发,旨在为学习者提供一套全面且深入的标准教程。...
《嵌入式Linux应用程序开发详解》是一本专为想要深入理解和实践Linux应用程序开发的读者精心编写的指南。这本书结合了理论与实践,旨在帮助读者掌握在嵌入式系统环境中进行Linux应用开发的关键技能。通过阅读本书,...
《嵌入式Linux应用程序开发标准教程(第2版)》是华清远见出版的一本针对嵌入式领域专业开发者的权威教程。这本书涵盖了从Linux基础知识到高级应用开发的多个方面,旨在帮助读者全面掌握在嵌入式环境中使用Linux进行...
《嵌入式Linux应用程序开发标准教程》第二版是一本深入探讨在嵌入式系统中如何进行Linux应用程序开发的专业书籍。其配套的PPT资源旨在帮助读者更直观、更有效地理解和学习书中的理论知识与实践技能。以下是根据PPT...
《嵌入式Linux应用程序开发标准教程》第二版全集,是一部深入探讨嵌入式系统开发的权威教程。这本书涵盖了从基础到高级的多个关键领域,包括Linux操作系统原理、C编程、进程控制、多线程编程、进程间通信、网络编程...
《嵌入式Linux应用程序开发标准教程(第2版)》主要分为3个部分,包括Linux基础、搭建嵌入式Linux环境和嵌入式Linux的应用开发。Linux基础部分从Linux基础、基本操作命令讲起,为Linux初学者能快速入门提供了保证。...
《嵌入式Linux应用程序开发标准教程(第二版)》是华清远见教育集团推出的一本经典教材,专门针对想要深入理解和实践嵌入式Linux应用程序开发的读者。这本教材凝聚了业界权威培训机构多年的经验和智慧,旨在帮助学习...
嵌入式Linux应用程序开发教程 第二版,完整版,充分讲叙了linux的基础命令,C编程基础,文件IO,进程控制及通信,多线程及驱动,QT开发
《嵌入式Linux应用程序开发标准教程》(第2版)是一本全面且深入的教材,旨在引导读者掌握在嵌入式系统中进行Linux应用程序开发的关键技术。本书从基础出发,逐步深入,适合初学者和有一定经验的开发者学习。 第一...
《嵌入式Linux应用程序开发标准教程》(第2版)是一部深入探讨嵌入式Linux系统应用开发的专业书籍,其光盘源代码包含了丰富的实例和练习,旨在帮助读者掌握实际操作中的技能。本教程覆盖了从基础到高级的多个重要...
总的来说,学习使用LINUX应用程序开发指南:使用GTK+ GNOME库,开发者将掌握创建具有专业外观和功能的Linux GUI程序的技能。这个过程涉及理解底层操作系统、图形界面原理,以及如何利用强大的工具集来优化用户体验。...
《嵌入式Linux应用程序开发标准教程》是华清远见所提供的专业嵌入式Linux开发培训教材,全书共分为12章,系统全面地讲述了嵌入式Linux应用程序的开发流程和技巧,适合对嵌入式Linux开发感兴趣的读者进行学习和参考。...
嵌入式linux应用程序开发期末考试题库及答案.doc
《嵌入式Linux应用程序开发详解》是一本专为初学者设计的Linux开发指南,旨在帮助读者快速掌握Linux应用程序编程的核心概念和技术。这本书深入浅出地介绍了如何在嵌入式环境中进行Linux应用开发,使得读者能轻松理解...
嵌入式Linux应用程序开发是现代科技领域中的一个重要分支,它涉及到硬件、操作系统、软件开发等多个层面。华清远见是一家在嵌入式技术培训方面有着深厚底蕴的机构,其提供的"嵌入式Linux应用程序开发"教程可能包含了...