把《C语言接口与实现》读薄之第一章:引言
1.1文学程序
文学程序(literate program):接口及其实现的代码与对其进行解释的正文交织在一起。文学程序由英文正文和带标签的程序代码块组成。例如,
〈compute x * y〉≡
sum = ;
for (i = ; i < n; i++)
sum += x[i]*y[i];
定义了名为〈compute x * y〉的代码块,其代码计算了数组x和y的点积。在另一个代码块中使用该代码块时,直接引用即可:
〈function dotproduct〉≡
int dotProduct(int x[], int y[], int n) {
int i, sum; 〈compute x o y〉
return sum;
}
文学程序可以按各个小片段的形式给出,并附以完备的文档。英文正文包含了传统的程序注释,这些并不受程序设计语言的注释规范的限制。
下面是文学编程系统的另一个特性,她有助于逐点对程序进行描述;下面以一个检测输入中相邻的相同单词的double程序,作为文学程序的例子:
先从定义根代码块来实现double,该代码块将使用对应于程序各个组件的其他代码块:
〈double.c 〉≡
〈includes 〉
〈data 〉
〈prototypes 〉
〈functions 〉
main函数处理double的参数。它会打开各个文件,并调用doubleword扫描文件:
〈functions 〉≡
int main(int argc, char *argv[]) {
int i; for (i = ; i < argc; i++) {
FILE *fp = fopen(argv[i], "r");
if (fp == NULL) {
fprintf(stderr, "%s: can't open '%s' (%s)\n",
argv[], argv[i], strerror(errno));
return EXIT_FAILURE;
} else {
doubleword(argv[i], fp);
fclose(fp);
}
}
if (argc == ) doubleword(NULL, stdin);
return EXIT_SUCCESS;
} 〈includes 〉≡
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
getword从打开的文件读取下一个单词,复制到buf [0..size 1]中,并返回1;在到达文件末尾时该函数返回0。
functions 〉+≡
int getword(FILE *fp, char *buf, int size) {
int c; c = getc(fp);
〈scan forward to a nonspace character or EOF 〉
〈copy the word into buf[..size-] 〉
if (c != EOF)
ungetc(c, fp);
return〈found a word? 〉;
} 〈prototypes 〉≡
int getword(FILE *, char *, int);
getword除了从输入获取下一个单词之外,每当遇到一个换行字符时都对linenum加1。doubleword输出时将使用linenum。
〈data 〉≡
int linenum; 〈scan forward to a nonspace character or EOF 〉≡
for ( ; c != EOF && isspace(c); c = getc(fp))
if (c == '\n')
linenum++; 〈includes 〉+≡
#include <ctype.h>
size的值限制了getword所能存储的单词的长度,getword函数会丢弃过多的字符并将大写字母转换为小写:
〈copy the word into buf[..size-] 〉≡
{
int i = ;
for ( ; c != EOF && !isspace(c); c = getc(fp))
if (i < size - )
buf[i++] = tolower(c);
if (i < size)
buf[i] = '\0';
}
剩下的代码逻辑是,如果buf中保存了一个单词则返回1,否则返回0:
〈found a word? 〉≡
buf[] != '\0'
doubleword读取各个单词,并将其与前一个单词比较,发现重复时输出。它只查看以字母开头的单词:
〈functions 〉+≡
void doubleword(char *name, FILE *fp) {
char prev[], word[]; linenum = ;
prev[] = '\0';
while (getword(fp, word, sizeof(word)) {
if (isalpha(word[]) && strcmp(prev, word)==)
〈word is a duplicate 〉
strcpy(prev, word);
}
}
〈prototypes 〉+≡ void doubleword(char *, FILE *); 〈includes 〉+≡
#include <string.h>
输出是很容易的,但仅当name不为NULL时才输出文件名及后接的冒号:
〈word is a duplicate 〉≡
{
if (name)
printf("%s:", name);
printf("%d: %s\n", linenum, word);
}
总结:整个程序的设计符合学习C语言经常提的:自顶向下,逐步细化,模块化!
1.2程序设计风格
上例double说明了本书中程序所使用的风格惯例。一般来说,较长且富于语义的名称用于全局变量和例程,而数学符号般的短名称则用于局部变量。
代码中几乎没有注释,因为围绕对应代码块的正文代替了注释。本书将效法C程序设计方面的典范,最低限度地使用注释。
库函数strcpy将一个字符串复制到另一个字符串中并返回目标字符串,对该函数的不同实现就说明了"地道的C语言"和新手C程序员编写的代码之间的差别,后一种代码通常使用数组:
char *strcpy(char dst[], const char src[]) {
int i; for (i = ; src[i] != '\0'; i++)
dst[i] = src[i];
dst[i] = '\0';
return dst;
}
"地道"的版本则使用指针:
char *strcpy(char *dst, const char *src) {
char *s = dst; while (*dst++ = *src++)
;
return s;
}
这两个版本都是strcpy的合理实现。指针版本使用通常的惯用法将赋值、指针递增和测试赋值操作的结果合并为单一的赋值表达式。它还修改了其参数dst和src,
这在C语言中是可接受的,因为所有参数都是传值的,实际上参数只不过是已初始化的局部变量。
1.3 效率
程序员似乎被效率问题困扰着。他们可能花费数小时来微调代码,使之运行得更快。遗憾的是,大部分这种工作都是无用功。当猜测程序的运行时间花费在何处时,程序员的直觉非常糟糕。
微调程序是为了使之更快,但通常总是会使之更大、更难理解、更可能包含错误。除非对执行时间的测量表明程序太慢,否则这样的微调没有意义。程序只需要足够快即可,不一定要尽可能快。
如果I/O占了程序运行时间的60%,在搜索例程中节省1%是无意义的。
微调:
- 微调通常会引入错误。最快崩溃的程序绝非胜者。可靠性比效率更重要;与交付足够快的可靠软件相比,交付快速但会崩溃的软件,从长远看来代价更高。
- 微调经常在错误的层次上进行。快速算法的直接简明的实现,比慢速算法的手工微调实现要好得多。例如,减少线性查找的内层循环的指令数,注定不如直接使用二分查找。
- 微调无法修复低劣的设计。如果程序到处都慢,这种低效很可能是设计导致的。当基于编写得很糟糕或不精确的问题说明给出设计时,或者根本就没有总体设计时,就会发生这种令人遗憾的情况。
一些C程序员在寻求提高效率的途径时,大量使用宏和条件编译。只要有可能,本书将避免使用这两种方法。使用宏来避免函数调用基本上是不必要的。仅当客观的 测量结果表明有问题的调用的开销大大超出其余代码的运行时间时,使用宏才有意义。操作I/O是较适宜采用宏的少数情况之一。例如,标准的I/O函数 getc、putc、getchar和putchar通常实现为宏。
条件编译通常用于配置特定平台或环境的代码,或者用于代码调试的启用/禁用。这些问题是实际存在的,但条件编译通常只是解决问题的较为容易的方法,而且总会使代码更难于阅读。如果应用程序必须在编译时配置,与C语言的条件编译工具相比,版本控制工具更擅长完成该工作。
把《C语言接口与实现》读薄之第一章:引言的更多相关文章
- 《Go 语言并发之道》读后感 - 第一章
<Go 语言并发之道>读后感 - 第一章 前言 人生路漫漫,总有一本书帮助你在某条道路上打通任督二脉,<Go 语言并发之道>就是我作为一个 Gopher 道路上的一本打通任督二 ...
- Swift中对C语言接口缓存的使用以及数组、字符串转为指针类型的方法
由于Swift编程语言属于上层编程语言,而Swift中由于为了低层的高性能计算接口,所以往往需要C语言中的指针类型,由此,在Swift编程语言刚诞生的时候就有了UnsafePointer与Unsafe ...
- C语言接口与实现实例
一个模块有两部分组成:接口和实现.接口指明模块要做什么,它声明了使用该模块的代码可用的标识符.类型和例程,实现指明模块是如何完成其接口声明的目标的,一个给定的模块通常只有一个接口,但是可能会有许多种实 ...
- [转]SQLITE3 C语言接口 API 函数简介
SQLITE3 C语言接口 API 函数简介 说明:本说明文档属作者从接触 SQLite 开始认识的 API 函数的使用方法, 由本人翻译, 不断更新. /* 2012-05-25 */ int sq ...
- 基于Oracle OCI的数据访问C语言接口ORADBI .
基于Oracle OCI的数据访问C语言接口ORADBI cheungmine@gmail.com Mar. 22, 2008 ORADBI是我在Oracle OCI(Oracle 调用接口)基础 ...
- 18 A GIF decoder: an exercise in Go interfaces 一个GIF解码器:go语言接口训练
A GIF decoder: an exercise in Go interfaces 一个GIF解码器:go语言接口训练 25 May 2011 Introduction At the Googl ...
- opencv的C语言接口和C++接口差别(入门篇)
opencv是一个开源的图像处理库,最经典的1.0版本号提供的接口都是C语言接口. 后来的opencv2.x版本号保留了C语言接口,可是提供了C++接口,当中的C语言接口仅仅是为了向后兼容,而C++接 ...
- GO语言学习(十八)Go 语言接口
Go 语言接口 Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口. 实例 /* 定义接口 */ type interface ...
- C语言学习书籍推荐《C语言接口与实现:创建可重用软件的技术》下载
<C语言接口与实现:创建可重用软件的技术>概念清晰.实例详尽,是一本有关设计.实现和有效使用C语言库函数,掌握创建可重用C语言软件模块技术的参考指南.书中提供了大量实例,重在阐述如何用一种 ...
随机推荐
- 【android】ImageView的src和background以及两者之间的神奇的差异
一.ImageView中XML属性src和background的差别: background会依据ImageView组件给定的长宽进行拉伸.而src就存放的是原图的大小,不会进行拉伸.src是图片内容 ...
- 基于PHP的crontab定时任务管理
BY JENNER · 2014年11月10日· 阅读次数:6 linux的crontab一直是server运维.业务开展的利器.但当定时任务增多时,管理和迁移都变得非常麻烦,并且easy出问题.以下 ...
- hdu Simpsons’Hidden Talents(kmp)
Problem Description Homer: Marge, I just figured out a way to discover some of the talents we weren’ ...
- 查询oracle sql运行计划,一个非常重要的观点--dba_hist_sql_plan
该文章的作者给予了极大的帮助长老枯荣,为了表达我的谢意. 这适用于oracle db版本号oracle 10g或者更高的版本号. 之所以说这种看法是非常重要的,因为观点是有之一awrsqrpt报告没有 ...
- MyEclipse2014 设备 checkstyle、PMD、findbugs 最简单的方法 详细说明
最近的实验需要的代码审查和应用程序性能优化.在需求MyEclipse安装某些插件,由于如今的MyEclipse版本号和大多数教程的不一样了,一些安装选项也已经改变,所以安装起来非常费事,通过不断的尝试 ...
- [转载]cookie
cookie概述 在上一节,曾经利用一个不变的框架来存储购物栏数据,而商品显示页面是不断变化的, 尽管这样能达到一个模拟 全局变量的功能,但并不严谨.例如在导航框架页面内右击,单击快捷菜单中的[刷新] ...
- hive 的分隔符、orderby sort by distribute by的优化
一.Hive 分号字符 分号是SQL语句结束标记,在HiveQL中也是,可是在HiveQL中,对分号的识别没有那么智慧,比如: select concat(cookie_id,concat(';',' ...
- 【转】HTTP协议两种提交参数的方式Form-data和raw
原文:http://www.cnblogs.com/zhangfei/p/5099036.html HTTP协议的接口测试中,使用到最多的就是GET请求与POST请求,其中POST请求有FORM参数提 ...
- EF4.1: Add/Attach and Entity States(EF中的实体状态转换说明)
实体的状态,连接以及 SaveChanges 方法 数据库上下文对象维护内存中的对象与数据库中数据行之间的同步.这些信息在调用 SaveChanges方法被调用的时候使用.例如,当使用 Add 方法传 ...
- windows+php5.5+apache2.4+tomcat+mod_jk配置
原因: 通常情况下apache执行的是80port,比方apache启动后执行localhost:80就能够出现It works页面,这里的80也能够不写,会默认的.而tomcat启动时默认的port ...