论坛» 综合技术» 物联网技术

Linux应用程序开发

高工
2008-10-09 14:57 1楼

Abstract

我的Linux应用程序开发笔记,从这里开始我的Linux开发之旅。


Table of Contents

1. C语言基础 1.1. 指针与数组2. Linux程序开发基础概念 3. 文件处理 4. Linux环境 Chapter 1. C语言基础

Table of Contents

1.1. 指针与数组

Linux是使用C语言开发的,基于Linux平台的应用程序开发,C语言是首选的开发语言。本章记录C语言的基本概念\ 和基础知识。

1.1. 指针与数组
  • C语言中专门用来存放内存地址的变量叫指针(pointer)变量,简称指针。

  • &运算符用来取得变量地址,

  • "*"运算符用来取得指针变量的值。

  • 数组名是地址

Chapter 2. Linux程序开发基础概念

在设置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的内容如下:

    #i nclude  void a(char *arg) { printf("function a,hello world %s\n",arg); }

    函数b的内容如下:

    #i nclude  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 #i nclude "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
  • 包含头文件,用#i nclude指令,可把包含的文件代码插入当前位置。如:

    <#i nclude 

    包含的文件可以用尖括号,也可用双引号,如:

    #i nclude "stdio.h"。

    不同之处是,使用尖括号表示在系统的包含目录(/usr/include)下查找该文件,而双引号表示在当前目录下查找包含文件。每行只能包含一个包含文件,要包含多个文件要用多个#i nclude指令。

  • 条件编译,格式如下:

    格式一,如果定义了标识符,则编译程序段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)的集合。

Chapter 3. 文件处理

在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用于分享内存。

创建文档并输入信息的示例代码:

#i nclude  main(void) { FILE *fp1; char c; fp1 = fopen("text.txt","w"); while ((c = getchar())!= '\n') putc(c,fp1); fclose(fp1); }

显示路径的示例代码

#i nclude  #i nclude  #i nclude  #i nclude  #i nclude  #i nclude  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); }
Chapter 4. Linux环境

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

获取命令行参数的示例代码:

#i nclude  #i nclude  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的值显示同来。

#i nclude  #i nclude  extern char **environ; int main() { char **env = environ; while(*env) { printf("%s\n",*env); env++; } }

linux和其它unix一样,使用GMT1970年1月1日子夜作为系统时间的开始,也叫UNIX纪元的开始。现在的时间表示为UNIX纪元至今经过的秒数。

#i nclude  time_t time(time_t *t); 显示系统时间的示例代码: #i nclude  #i nclude  #i nclude  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()函数以友好方式返回当前时间,它的函数声明格式:

#i nclude  char *ctime(const time_t *timeval); 示例: #i nclude  #i nclude  int main(void) { time_t time1; (void)time(&time1); printf("The date is: %s\n",ctime(&time1)); }

用mkstemp()函数创建临时文件。声明:

#i nclude int mkstemp(char * template); 示例: #i nclude  int main(void) { char template[] = "template-XXXXXX"; int fp; fp = mkstemp(template); printf("template = %s\n", template); close(fp); }

获取用户信息。

声明: #i nclude  #i nclude  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 示例代码: #i nclude  #i nclude  #i nclude  #i nclude  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()函数获取主机名。

函数声明: #i nclude  int gethostname(char *name, size_t namelen); /* 主机名返回给name变量 */ 示例代码: #i nclude  #i nclude  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命令返回的信息一样。

函数声明: #i nclude  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 示例代码: #i nclude  #i nclude  #i nclude  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()函数处理日志信息。

函数声明: #i nclude  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 */ 示例代码: #i nclude  #i nclude  int main(void) { FILE *f; f = fopen("abc","r"); if(!f) syslog(LOG_ERR|LOG_USER,"test - %m\n"); }

上面的日志信息由系统自动给出,我们也可过滤日志信息。用到以下函数:

#i nclude  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. 示例代码: #i nclude  #i nclude  #i nclude  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
共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册]