《C编程.中级C》8.库

库中C是一组功能和声明,由其他程序暴露以供使用。因此,库包含在文件中表示的接口.h(称为“标题”)和在文件中表示的实现.c。此.c文件可能已预编译或无法访问,或者程序员可能可以使用。(注意:库可以调用其他库中的函数,例如标准C或数学库来执行各种任务。)

库的格式因操作系统和正在使用的编译器而异。例如,在Unix和Linux操作系统中,库由一个或多个目标文件组成,这些目标文件由目标代码组成,目标代码通常是编译器的输出(如果源语言是C或类似的东西)或汇编程序(如果源语言是汇编语言)。然后,这些目标文件由ar archiver 以存档的形式转换为一个库(一个程序,它接收文件并将它们存储在一个更大的文件中而不考虑压缩)。库的文件名通常以“lib”开头,以“.a”结尾; 例如libc.afile包含标准C库和“libm.a”数学例程,链接器将链接到该数学例程。其他操作系统(如Microsoft Windows)使用库的“.lib”扩展名和对象的“.obj”扩展名文件。Unix环境中的某些程序(如lex和yacc)生成的C代码可以与libl和liby库链接以创建可执行文件。

我们将使用一个包含一个函数的库作为示例:一个从命令行解析参数的函数。命令行上的参数可以是它们自己:

    -一世

有一个可选的参数连接到字母:

    -ioptarg

或者将参数放在一个单独的argv-element中:

    -i optarg

除了函数之外,该库还有四个声明导出:三个整数和一个指向可选参数的指针。如果参数没有可选参数,则指向可选参数的指针将为null。

为了解析所有这些类型的参数,我们编写了以下“getopt.c”文件:

#include  <stdio.h> / *表示fprintf()和EOF * /
#include  <string.h> / * for strchr()* /
#include  “getopt.h”/ *一致性检查* /

/ *变量* / 
int  opterr  =  1 ;                  / * getopt打印错误,如果这是* / 
int  optind  =  1 ;                  / *令牌指针* / 
int  optopt ;                      / *选项字符传回用户* / 
char  * optarg ;                    / * flag参数(或值)* /

/ * function * / 
/ *返回选项字符,EOF如果没有或者?如果有问题。
	函数的参数:
	argc,argv  -  main()函数的参数。“ - ”的参数将
	停止处理。
	opts  - 包含有效选项字符的字符串。
	选项字符后跟冒号(:)表示
	该选项具有必需参数。
* / 
int 
getopt  (int  argc , char  ** argv , char  * opts )
{ 
	static  int  sp  =  1 ;             / *字符索引到当前令牌* /
	注册 char  * cp ;             / *指向当前令牌的指针* /
	
	if  (sp  ==  1 )
	{ 
		/ *检查更多类似标志的标记* / 
		if  (optind  > =  argc  ||  argv [ optind ] [ 0 ]  !=  ' - '  ||  argv [ optind ] [ 1 ]  ==  '\ 0' )
			返回 EOF ; 
		else  if  (strcmp  (argv [ optind ], “ - ” ) ==  0 )
		{ 
			optind ++ ;
			返回 EOF ; 
		} 
	}
	
	optopt  =  argv [ optind ] [ sp ];
	
	if  (optopt  ==  ':'  ||  (cp  =  strchr  (opts , optopt )) ==  NULL )
	{ 
		if  (opterr )
			fprintf  (stderr , “%s:invalid option  - '%c' \ n ” , argv [ 0 ], optopt );
		
		/ *如果此标记中没有剩余字符,则移至下一个标记* / 
		if  (argv [ optind ] [ ++ sp ]  ==  '\ 0' )
		{ 
			optind ++ ; 
			sp  =  1 ; 
		}
		
		回来 '?' ; 
	}
	
	if  (* ++ cp  ==  ':' )
	{ 
		/ *如果需要一个值,得到它* / 
		if  (argv [ optind ] [ sp  +  1 ]  !=  '\ 0' )
			/ *标志值是其余的当前令牌* / 
			optarg  =  argv [ optind ++ ]  +  (sp  +  1 ); 
		else  if  (++ optind  > =  argc )
		{ 
			if  (opterr )
				fprintf  (stderr , “%s:选项需要参数 - '%c' \ n ” ,
							argv [ 0 ], optopt ); 
			sp  =  1 ; 
			回来 '?' ; 
		} 
		else 
	                / *标志值是下一个标记* / 
		        optarg  =  argv [ optind ++ ]; 
		sp  =  1 ; 
	} 
	else 
	{ 
		/ *设置为查看令牌中的下一个char,下次* / 
		if  (argv [ optind ] [ ++ sp ]  ==  '\ 0')
		{ 
			/ *当前令牌中没有更多,所以设置下一个令牌* / 
			sp  =  1 ; 
			optind ++ ; 
		} 
		optarg  =  0 ; 
	} 
	返回 optopt ; 
}  
/ *文件结尾* /

接口将是以下“getopt.h”文件:

#ifndef GETOPT_H 
	#define GETOPT_H

	/ * export variables * / 
	extern  int  opterr , optind , optopt ; 
	extern  char  * optarg ;

	/ * export function * / 
	int  getopt (int , char  ** , char  * ); 
#万一

/ *文件结尾* /

程序员至少要有一个接口文件来弄清楚如何使用库,尽管一般来说,库程序员还编写了有关如何使用库的文档。在上面的例子中,文档应该说提供的参数**argv*opts两者都不应该是空指针(或者为什么你还要使用该getopt函数?)。具体而言,它通常说明每个参数的用途以及在哪些条件下可以预期的返回值。使用库的程序员通常对库的实现不感兴趣 – 除非实现有错误,在这种情况下他会想要以某种方式抱怨。

getopts库的实现和使用该库的程序都应该声明#include "getopt.h",以便引用相应的接口。现在,库与程序“链接” – 包含main()函数的程序。该程序可能涉及许多接口。

在某些情况下,只是放置#include "getopt.h"可能看起来正确,但仍然无法正确链接。这表示库未正确安装,或者可能需要一些其他配置。您必须检查编译器的文档或库的文档,以了解如何解决此问题。

放在头文件中的内容

作为一般规则,标头应包含任何声明和宏定义(预处理器#define),以便程序中的其他模块“看到”。

可能的声明:

  • struct,union和enum声明
  • typedef声明
  • 外部函数声明
  • 全局变量声明

在上面的getopt.h示例文件,一个函数(getopt)声明及四个全局变量(optindoptoptoptargopterr)也宣布。变量是使用extern头文件中的存储类说明符声明的,因为该关键字指定“实际”变量存储在别处(即getopt.c文件)而不是头文件中。

#ifndef GETOPT_H/#define GETOPT_H诀窍是俗称包括警卫。这样使用,如果getopt.h文件在翻译单元中被多次包含,则该单元只能看到一次内容。或者,#pragma once在头文件中也可以用来实现同样的事情。

猜你想读:《C编程.高级C》1.常见做法

THE END
分享