dbm数据库源代码分析(4):头文件部分(续)
(7)proto.h:dbm例程的所有函数原型声明。包括内部接口和gdbm的用户接口。ndbm和dbm的兼容性实现也要用到这里的各个函数。这些函数的功能在具体的源代码解剖时会有详细说明。注意一些老式的非标准的C编译器中函数声明不能带参数列表,而标准的C编译器中函数声明必须带参数列表。为了兼容性,这里把函数的参数列表arg(包括函数名后面的括号)抽离出来定义成宏__P(arg),当编译器是标准编译器时(用标准C编译器内部定义的__STDC__宏来指定),__P(arg)被展开成arg,从而带参数列表。当编译器是非标准编译器时,__P(arg)被展开成(),从而不带参数列表。
/* proto.h - dbm例程的原型(所有函数原型) */
#ifndef __P
#ifdef __STDC__
#define __P(args) args
#else
#define __P(args) ()
#endif
#endif
/* 来自于bucket.c */
void _gdbm_new_bucket __P((gdbm_file_info *, hash_bucket *, int));
void _gdbm_get_bucket __P((gdbm_file_info *, int));
void _gdbm_split_bucket __P((gdbm_file_info *, int));
void _gdbm_write_bucket __P((gdbm_file_info *, cache_elem *));
/* 来自于falloc.c */
off_t _gdbm_alloc __P((gdbm_file_info *, int));
void _gdbm_free __P((gdbm_file_info *, off_t, int));
int _gdbm_put_av_elem __P((avail_elem, avail_elem [], int *, int));
/* 来自于findkey.c */
char *_gdbm_read_entry __P((gdbm_file_info *, int));
int _gdbm_findkey __P((gdbm_file_info *, datum, char **, int *));
/* 来自于hash.c */
int _gdbm_hash __P((datum));
/* 来自于update.c */
void _gdbm_end_update __P((gdbm_file_info *));
void _gdbm_fatal __P((gdbm_file_info *, char *));
/* 来自于gdbmopen.c */
int _gdbm_init_cache __P((gdbm_file_info *, int));
/* 用户可以调用的例程(函数).... */
void gdbm_close __P((gdbm_file_info *));
int gdbm_delete __P((gdbm_file_info *, datum));
datum gdbm_fetch __P((gdbm_file_info *, datum));
gdbm_file_info *gdbm_open __P((char *, int, int, int, void (*) (void)));
int gdbm_reorganize __P((gdbm_file_info *));
datum gdbm_firstkey __P((gdbm_file_info *));
datum gdbm_nextkey __P((gdbm_file_info *, datum));
int gdbm_store __P((gdbm_file_info *, datum, datum, int));
int gdbm_exists __P((gdbm_file_info *, datum));
void gdbm_sync __P((gdbm_file_info *));
int gdbm_setopt __P((gdbm_file_info *, int, int *, int));
int gdbm_fdesc __P((gdbm_file_info *));
(8)ndbm.h:ndbm用户要包含的头文件。包含dbm_store操作的参数标识、datum结构、DBM结构、ndbm的所有用户接口声明,其中dbm_error和dbm_clearerr是用宏来定义的。
/* ndbm.h - ndbm用户要包含的头文件 */
/* 用dbm_store作简单地插入或覆盖操作时的参数 */
#define DBM_INSERT 0
#define DBM_REPLACE 1
/* 数据和关键字的结构,本定义具有兼容性 */
typedef struct {char *dptr;int dsize;} datum;
/* 文件信息头 */
typedef struct {int dummy[10];} DBM;
/* ndbm的所有用户接口声明,有些是用宏来定义 */
extern DBM *dbm_open ();
extern void dbm_close ();
extern datum dbm_fetch ();
extern int dbm_store ();
extern int dbm_delete ();
extern int dbm_delete ();
extern datum dbm_firstkey ();
extern datum dbm_nextkey ();
#define dbm_error(dbf) (0)
#define dbm_clearerr(dbf)
extern int dbm_dirfno ();
extern int dbm_pagfno ();
extern int dbm_rdonly ();
(9)dbm.h:dbm用户要包含的头文件。包含datum结构、dbm的所有用户接口声明。
/* dbm.h - dbm用户要包含的头文件 */
/* 数据和关键字的结构,本定义具有兼容性 */
typedef struct {char *dptr;int dsize;} datum;
/* dbm的所有用户接口声明 */
extern int dbminit ();
extern datum fetch ();
extern int store ();
extern int delete ();
extern int delete ();
extern datum firstkey ();
extern datum nextkey ();
extern int dbmclose ();
(10)gdbm.proto和gdbm.proto2:编译时会合并成gdbm.h头文件,这是gdbm用户要包含的头文件。其中gdbm.proto2只包含了一个用户接口声明,其余都在gdbm.proto中(记录错误码的全局变量在gdbmerrno.h中,编译时会复制到gdbm.h中)。包含了各个操作的参数标识、datum结构、GDBM_FILE结构、gdbm的所有用户接口声明。注意其中的预编译格式
#ifdef __cplusplus
extern "C" {
#endif
//一段代码,或者一系列函数原型声明
#ifdef __cplusplus
}
#endif
这里__cplusplus是C++编译器中的内部定义的宏,C编译器中没有这个宏。这个格式的含义是:如果这是一段C++的代码(即用C++编译器来编译),那么加入extern "C"{...}处理其中的代码。即用C语言的方式来处理其中的代码。这主要是因为C++和C对产生的函数名字的处理是不一样的。C语言中没有重载函数的概念,所以C编译器编译的程序里,所有函数只有函数名对应的入口。而由于 C++语言有重载函数的概念,如果只有函数名对应入口,则会出现混淆。所以C++编译器编译的程序,应该是用函数名加参数类型列表来对应到入口,有时还包括返回类型等(从其生成的汇编代码中可以看出来,用gcc试试就可以知道了)。当我们在C++中要使用一个用C语言编写的库时,编译时是使用C++的方式来处理你的代码中用到的C函数,但是实际上链接的库文件却是用C的方式来处理函数的,这样经常会出现链接过不去的错误,因为链接器找不到函数。上面的extern "C"就是告诉C++编译器,这是一个用C写成的库文件,请用C的方式来链接它们。总之,当我们用C语言开发项目时,若希望用户在老式的非标准的C编译器,或者在C++中也能使用它们时,特别注意在导出的头文件中要使用__P宏、_cplusplus宏、extern"C"等。
/* gdbm.proto - gdbm用户要包含的头文件,会被编译到gdbm.h中去 */
/* 多重包含时的保护符 */
#ifndef _GDBM_H_
#define _GDBM_H_
/* gdbm_open操作的参数标识 */
#define GDBM_READER 0 /* 只读 */
#define GDBM_WRITER 1 /* 可读可写,但不能创建 */
#define GDBM_WRCREAT 2 /* 如果没有发现,则创建db(可写) */
#define GDBM_NEWDB 3 /* 总是创建新的db(可写) */
#define GDBM_FAST 0x10 /* 快速写入!=> 没有fsyncs时。已经过时了 */
#define GDBM_SYNC 0x20 /* 对磁盘的同步操作(sync),即将所有未写的系统缓冲区写到磁盘中 */
#define GDBM_NOLOCK 0x40 /* 不对文件做锁定操作 */
/* gdbm_store的参数,这个函数用来插入数据或覆盖已有的数据(当给定的关键字在数据库中已经存在时) */
#define GDBM_INSERT 0 /* 不覆盖数据库中的数据 */
#define GDBM_REPLACE 1 /* 用新值覆盖已有的值 */
/* gdbm_setopt的参数,这个函数用来指定要执行的操作类型 */
#define GDBM_CACHESIZE 1 /* 设置缓存大小 */
#define GDBM_FASTMODE 2 /* 打开或关闭快速模式,已经过时 */
#define GDBM_SYNCMODE 3 /* 打开或关闭同步操作(sync) */
#define GDBM_CENTFREE 4 /* 保持文件头中的所有空闲数据块 */
#define GDBM_COALESCEBLKS 5 /* 试着合并空闲数据块 */
/* 数据和关键字的结构,本定义具有兼容性 */
typedef struct {char *dptr;int dsize;} datum;
/* 文件信息头 */
typedef struct {int dummy[10];} *GDBM_FILE;
/* 确定C(++)编译器是否需要完整的函数原型声明 */
#ifndef __P
#if defined(__STDC__) || defined(__cplusplus) || defined(c_plusplus)
#define __P(x) x
#else
#define __P(x) ()
#endif
#endif
/* 外部变量,存放gdbm的版本信息 */
extern char *gdbm_version; /* GDBM的C++支持 */
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
/* 下面是所有的例程集 */
extern GDBM_FILE gdbm_open __P((char *, int, int, int, void (*)()));
extern void gdbm_close __P((GDBM_FILE));
extern int gdbm_store __P((GDBM_FILE, datum, datum, int));
extern datum gdbm_fetch __P((GDBM_FILE, datum));
extern int gdbm_delete __P((GDBM_FILE, datum));
extern datum gdbm_firstkey __P((GDBM_FILE));
extern datum gdbm_nextkey __P((GDBM_FILE, datum));
extern int gdbm_reorganize __P((GDBM_FILE));
extern void gdbm_sync __P((GDBM_FILE));
extern int gdbm_exists __P((GDBM_FILE, datum));
extern int gdbm_setopt __P((GDBM_FILE, int, int *, int));
extern int gdbm_fdesc __P((GDBM_FILE));
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
/* gdbm.proto2 - 额外的函数原型声明,会被编译到gdbm.h中去 */
/* GDBM的C++支持 */
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
extern char *gdbm_strerror __P((gdbm_error));
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
#endif
(11)getopt.h:包含了getopt、getopt_long、getopt_long_only函数,以及一个内部使用的函数_getopt_internal。getopt用来解析命令行的选项,在POSIX对它有详细的规范。它处理短选项,即“-c value“的格式,c是单个字符的短选项名,value是这个选项关联的值,多个短选项可以合并在一块(从而可有多个字符,但每个字符都是一个选项)。循环调用getopt就可以依次得到每个选项。getopt返回agrv数组中的下一个选项字符,遇到未知选项时,getopt返回问号(?),并把它保存到optopt中;遇到需要关联值的选项但未提供关联值时,getopt返回冒号(:)。外部变量optarg保存当前处理的选项的关联值(如果有的话);optind保存第一个非选项的索引;遇到未知选项时opterr会变成非零值,getopt就会向stderr打印一条错误信息;未知选项保存在optopt中。对GNU版本的getopt,在扫描命令行时,每处理完一个选项,就会重写argv数组,把所有非选项都集中在一起,到最后处理完所有选项后,argv数组只会保存各个非选项的字符串,从argv[optind]开始可以访问这些非选项的字符串。
getopt_long和getopt_long_only是GNU对getopt的扩展,它支持处理长选项,即“--string=value”,string是长选项名(是一个字符串),value是其关联的值。
getopt系列函数现在已经成为了C函数库的一部分,在Linux等现代的类UNIX系统中都有提供。getopt在<unistd.h>中 。作为扩展的getopt_long、getopt_long_only等在<getopt.h>中,且使用时必须包含有#define _GNU_SOURCE,还需要用到struct option结构。这里提供getopt.h及其源代码实现getopt.c只是为了向后兼容(因为以前的UNIX系统可能并没有提供这些设施)。因此这里并不准备对它们进行解剖。
转载于:https://my.oschina.net/abcijkxyz/blog/723150
dbm数据库源代码分析(4):头文件部分(续)相关推荐
- dbm数据库源代码分析(3):头文件部分
现在解剖gdbm的头文件部分的源码. (1)autoconf.h:由configure脚本根据autoconf.h.in模板生成.autoconf.h为平台相关的的头文件.函数.库等定义常量标志 ...
- 结合编译过程,分析C++头文件和源文件的区别
编译过程 简单的说其实要理解C文件与头文件(即.h)有什么不同之处,首先需要弄明白编译器的工作过程,一般说来编译器会做以下几个过程: 预处理阶段 词法与语法分析阶段 编译阶段,首先编译成纯汇编语句,再 ...
- linux关机机器语言,Linux 核心源代码分析 - 第十章 开机 关机 [续二] [超星]...
版权声明:本文档录自超星阅览器"免费图书馆"中的<Linux 核心源代码分析>.原文为扫描版,本文本文档是在下(大天赐)[http://blog.sina.com.cn ...
- Mysql源代码分析系列
Mysql源代码分析系列(2): 源代码结构 Mysql源代码主要包括客户端程序代码,服务器端代码,测试工具和一些库构成,下面我们对比较重要的目录做些介绍. BUILD 这个目录在本系列的上篇文章中我 ...
- YCM代码补全插件找不到c++头文件
开发环境: Ubuntu22.04 LTS x86_64架构Intel CPU YCM(YouCompleteMe)是一款用于vim编辑器的强大代码补全插件. YCM提供许多强大功能: 代码补全: 语 ...
- C++:include:理解 C++ 中的头文件和源文件的作用
关于头文件和源文件我们主要围绕: C++编译模式, 声明和定义区别, 符号只能被定义一次, 符号被定义在多个源文件,但是一个源文件只能定义一次 这四个方面来分析论述 1:C++ 编译模式 在一个C++ ...
- C++ 笔记(25)— 理解 C++ 中的头文件和源文件的作用
1. C++ 编译模式 通常,在一个 C++ 程序中,只包含两类文件: .cpp 文件,被称作 C++ 源文件,里面放的都是 C++ 的源代码 .h 文件,被称作 C++ 头文件,里面放的也是 C++ ...
- C++之头文件与源文件
(转) 一.C++编译模式 通常,在一个C++程序中,只包含两类文件--.cpp文件和.h文件.其中,.cpp文件被称作C++源文件,里面放的都是C++的源代码:而.h文件则被称作C++头文件 ...
- Linux的目录结构和头文件相关;哪里找- sys/types.h, sys/stat.h
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/qq_29757283/article/ ...
最新文章
- #舍得Share#Flash Media Server4.5迅雷高速下载地址by lwxshow
- Chrome中的from memory cache与from disk cache
- HDU 3537 Daizhenyang's Coin
- Python之PIL库
- (7) hibernate之级联cascade和关系维持inverse
- 【python】pycharm启动 一直index,无法运行
- linux python复制安装,复制一个Python全部环境到另一个环境,python另一个,导出此环境下安装的包...
- pythonjava app切出后无网络连接_写了一个java的Server 用python的client访问却访问不通问题。...
- IC卡应用系统开发-(一)卡片读写
- 《Android移动应用开发》 复习题(一)
- 各个行业的前端静态页面模板
- Speed Gear(变速精灵XP) V6.0 - 免费版,破解版,绿色版
- xp 游戏计算机没有了怎么办,我的xp系统没有自带游戏怎么办
- STM32 自定义串口协议
- 微信小程序-image标签
- Windows Server2012搭建邮件服务器
- 解决stm32下载错误 “Could not stop Cortex-M device.Please check the JTAG cable.“
- 安装dreamwaver
- 公司新加了一台友宝自动售货机引发的思考-适配器模式
- Python使用pngquant实现批量压缩图片