上章回顾
数组和指针相同与不同
通过指针访问数组和通过数组访问指针
指针在什么时候可以加减运算
函数指针的申明和调用
函数数组和数组函数
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
附录二
附录二
C语言标准库
C语言标准库
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
预习检查
NULL和NUL有什么差别 字符串操作有哪几个常用函数
memcpy和strcpy有什么差别
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
课程目标
本章概述
重点
难点
对标准C语言的补充,以及一些常用的特性。
本章目标
了解一些C语言特殊的宏定义 掌握函数可变参数的应用
理解NULL, offsetof, errno宏或函数
掌握函数可变参数列表难点 C语言库的日期函数操作
函数的可变参数列表 标准C的异常处理机制
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
本章结构
C标准语言库概要和应用 C标准语言库概要和应用
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
标准语言库概述
标准语言库概述
标准C语言函数 标准C语言函数
主要库文件 主要库文件
标准库应用总结
标准库应用总结
2.1 标准语言概述 函数库简介
C语言标准库的历史 标准库函数优势 独立环境和宿主环境
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.1.1 函数库简介 标准c语言包括语言标准和一组标准库
支持字符和字符串、输入与输出、数学函数、期与时
间转换、动态存储分配和其他特性
预处理器命令#include,引用这个库的头文件
例:
下列程序段中头文件math.h使程序能够访问余弦函数cos。 #include <math.h>
double x,y;
x = cos(y);
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.1.1 函数库简介 对定义为函数的库功能,标准C语言允许实现提供除真
正函数以外的同名函数式宏
例:
假设担心math.h中已有名为cos的宏,则可以用下面两种
方法引用基础函数。两者都利用宏名后面不能紧跟一个开 括号的特点,避免扩展同名函数或宏cos。
#include<math.h>
double a,b,(*p)(double);
...
p = &cos;
a= (*p)(b); /* calIs function cos,always */ a= (cos)(b); /* calls function cos,always */
也可以取消所有涉及到的宏的定义: #include<math.h>
#undef cos
...
嵌入式家园 www.embedclub.com
a = cos(b); /* calls function cos,always */
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.1.2 C语言标准库的历史 C语言提供的标准函数库,函数库通过#include进行引用
在C89标准中:
<assert.h> <ctype.h> <errno.h> <float.h> <limits.h> <locale.h> <math.h> <setjmp.h> <signal.h> <stdarg.h> <stddef.h> <stdio.h> <stdlib.h> <string.h> <time.h>
在95年的修正版中
<iso646.h> <wchar.h> <wctype.h>
在C99中增加了六个函数库
<complex.h> <fenv.h> <inttypes.h> <stdbool.h> <stdint.h>
<tgmath.h>
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.1.3 标准库函数优势
准确性 高效性 可移植性
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.1.4 独立环境和宿主环境
“独立(free—standing)”系统 嵌入式系统可以不要任何类型的文件系统,也可以基本上不
要操作系统
不要求它们提供除语言本身以外的任何东西
宿主(hosted)”环境 程序运行在RC机、大型机或者介于两者之间的计算机上
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.2 标准C语言函数 标准C语言函数
C++兼容性
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.2.1标准C语言函数 如何从标准c语言定义得到传统c语言库函数定义
消除任何使用标准c语言类型的函数,如long long与_Complex,或 消除标准c语言中新增的函数(C89或C99).
删除限定符const、restrict与volatile 删除数组声明符括号内使用的static. 将类型void * 换成char * ,将size_t换成int。
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.2.1标准C语言函数 库函数注意事项
库名原则上是保留字。编程人员不能定义与标准库名称同名的外部
对象。
库头文件或文件名可以内置在实现中,但仍然要被包括之后才能访
问其名称
编程人员可以多次按任意顺序包括库头文件
例 下面的方法可以保证库头文件不被包括多次: /* I Header Btddef.H */
#ifndef _STDDEF /* Don.t try to redeclare */ #define _STDDEF l
typedef int ptrdiff_t; .../* 0ther definitions */
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git#endif
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.2.2 C++兼容性 C++语言包括标准C语言运行库,但增加了几个C++
特定库 不能从c语言程序中调用c++函数,但c++提供了从
C++中调用c语言函数的方法 在C++中,声明c语言函数时有两个要求
函数声明要使用标准c语言原型,因为c++要求原型。 外部c语言要显式地标为具有c语言连接,即在c++的存储类extern后面加
上字符串“C”。
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.2.2 C++兼容性 c语言函数中调用另一C语言函数
extern int f(void); c++中调用C语言函数
extern“C“int f(void); c++中要声明一组c语言函数,则可以对所有c语言函
数采用连接规范:
extern“C“{
double sqrt(double x);
int f(void);
......
}
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.2.2 C++兼容性 从C语言或c++调用头文件library.h
在头文件中包括extern “C”声明(条件预编译__cplusplus宏),表 示这是个c++程序。
/* File library.h */ #ifdef __cplusplus
extern“c” { #endif
/* C declarations */ #ifdef __cplusplus
}
用正常c语言声#e明ndif编写头文件,要求c++用户用# include命令包装连接声明
extern “C“ { #include”library.h“
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git}
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3 主要的库文件
stddef.h math.h ctype.h erron.h stdbool.h iso645.h assert.h
stdio.h stdlib.h string.h stdarg.h time.h setjmp.h signal.h
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.1 Stddef.h
语法概要之定义
#include<stddef.h> #define NULL ......
typedef ...
ptrdiff_t; size_tj wchar_t;
typedef ...
typedef ...
#define offsetof(type,member-designator)
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.1 Stddef.h
NULL
size_t
null指针常量
0 转换为类型void的0
ptrdiff_t
实现定义的带符号整型
是两个指针相减所得到的类型
sizeof运算符得到的无符号整型
offsetof
扩展一个整型常量表达式
#define offsetof(type,memb)((size_t)&((type*)0)->memb)
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.1 Stddef.h
例:对于sizeof(int)为4的字节寻址计算机
#include<Stddef.h>
struct s{int a; int b;}x;
程序运行结果是:
diff的值为1 size的值为4
offset的值为4
size_t size,offset; ptrdiff_t diff;
Diff = &x.b-&x.a;
Size = sizeof(x.a); offset=offsetof(struct s,b);
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.2 math.h
双精度浮点数的精度进行操作
参数传递和错误处理
如果传递过来的参数不在其定义域内,函数会返回一些不确定的值 ,并将变量errno置为EDOM。
如果返回值太大,无法用一个double类型表示(造成上溢),这些函数 会返回HUGEVAL,并将errno置为ERANGE。
如果函数结果太小,无法表示,则函数返回0,errno是否设置为 ERANGE由实现确定
EDOM,ERANGE和HUGEVAL都在math.h中定义。
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.3 ctype.h
字符处理有两类函数:分类与转换
分类函数的名称以is开头 转换函数的名称以to开头
宽字符进行运算的分类与转换函数
分类函数----isw 转换函数----tow
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.3 ctype.h
字符处理有两类函数:分类与转换
分类函数的名称以is开头 转换函数的名称以to开头
宽字符进行运算的分类与转换函数
分类函数----isw 转换函数----tow
通用函数
分类函数wcstrans与iswctrans 转换函数 wctrans与towctrans
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.3 ctype.h
例:
#inelude<ctype.h> #define TRUE 1 #define FALSE 0
int is_id(const char *s) {
}
char ch;
if ((ch= *s++) ==‘\0’) return FALSE; /*empty string*/ if(!(isalpha(ch)||ch ==‘_’)) return FALSE;
while ((ch = *s++)!=‘\0’)
{
if(!(isalnum(ch) || ch==‘_’)) return FALSE; }
return TRUE;
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.4 erron.h
语法概要
#include<errno.h>
extern int errno; or # define errno ... #define EDOM ...
#define ERANGE #define ETLSEQ
... ...
#include<stdio.h>
void perror(const char *s)
#include<string.h>
char *strerror(int errnum)
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.4 erron.h
errno
保存库程序中实现定义的错误码,通常被定义为errno.h 中以E开头的宏 在标准c语言中,errno不能是变量,但可以扩展成int类型的任何可修改的
lvalue的宏。 errno用法
例 errno的常见用法是在调用库函数之前先清零,随后再进行检查:
errno=0; x = sqrt(y); if(errno)
{
printf(”?sqrt falled,code%d\n”,errno);
x=0; }
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.4 erron.h
c语言实现通常定义一组标准错误码:
EDOM 参数不在数学函数能接受的域中。例如log函数的参数不能为负数参数
ERANGE 数学函数的结果超出范围
EILSEQ 翻译多字节字符序列时遇到的编码错误。这个错误最终会由mbrtowc或
wcrtomb发现,它们又被其他宽字符函数调用(c89增补l) 函数strerror返回一个错误消息字符串的指针,其内容是由实现定义的,字符串不
能修、但可以在后续调用strerror函数时覆盖 函数perror在标准错误输出流中打印下面的序列:参数字符串s、冒号、空格、包
errno中当前错误码的错误短消息和新行符
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.4 erron.h
perror 使用例子: perror 函数代替printf函数
#include<math.h> #include<errno.h>
}
...... errno=0;
x = sqrt(y); if(errno){
perror(“sqrt failed”); x=0;
如果调用sqrt失败,则输出如下: sqrt failed:domain error
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.5 bool、false、true 语法概要
#include <stdbool.h>
#define bool _Bool /*无符号整数类型,只能保存数值0和1 */ #define false 0
#define true 1
#define __bool_true_false_are_define 1
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.6 iso646.h
语法概要
#include <iso646.h> #define and && #define and_eq &= #define bitand & #define bitor | #define compl ~ #define not ! #define not_eq != #define or || #define or_eq |= #define xor ^ #define xor_eq ^=
如果调用sqrt失败,则输出如下: sqrt failed:domain error
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.7 assert.h
Assert.h函数提供标准控制流扩展
语法概要
作用
#include<assert.h> #ifndef NDGBUG
void assert(int expression); #else
#define assert(x) ((void)0) #endif
标准输出流中打印一个诊断消息(参数文本、文件名(_FILE_)和号(_LINE_) ) 调用abort函数或exit函数终止程序
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.7 assert.h
例:测试一个条件并可能使程序终止
#include <assert.h> #include <stdio.h> #include <stdlib.h> struct ITEM
{
int key;
int value; };
void additem(struct ITEM *itemptr) {
assert(itemptr != NULL); }
int main(void) {
additem(NULL); return 0;
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
}
2.3.8 string.h
C 常用字符串处理函数及使用示例 char *strncat(char *s1, const char *s2, size_t n)
将字符串s2中最多n个字符添加到字符串s1的后面。s2的第一个字符重定义s1 的null终止符。返回s1的值
int strcmp(const char *s1, const char *s2)
比较字符串s1和字符串s2。函数在s1等于、小于或大于s2时分别返回0、小于0 或大于0的值
int strncmp(const char *s1, const char *s2, size_t n)
比较字符串s1中的n个字符和字符串s2。函数在s1等于、小于或大于s2时分别 返回0、小于0或大于0的值
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.8 string.h
C 常用字符串处理函数及使用示例 char *strcpy(char *s1, const char *s2)
将字符串s2复制到字符串数组s1中,返回s1的值 char *strncpy(char *s1, const char *s2, size_t n)
将字符串s2中最多n个字符复制到字符串数组s1中,返回s1的值 char *strcat(char *s1, const char *s2)
将字符串s2添加到字符串s1的后面。s2的第一个字符重定义s1的null终止符。 返回s1的值
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.8 string.h
C 常用内存处理函数
void *memccpy(void *destin,void *source, char ch,unsigned n)
若复制了ch,则返回直接跟随ch的在destin中的字节的一个指针 Void * memcpy(void *destin,void *source,unsigned ,unsigned n)
从source复制一个n字节的块到destin.如果源块和目标块重迭,则选择复制方向 void *memchr(void *s,char ch,unsigned n)
返回在s中首先出现ch的一个指针;如果在s数组中不出现ch,就返回NULL.. void *memcmp(void *s1,void *s2,unsigned n)
比较正好是n字节长的两个字符串s1和s2.些函数按无符号字符比较字节
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.8 string.h
C 常用内存处理函数
int memicmp(void *s1,void *s2,unsigned n)
比较s1和s2的前n个字节,不管字符大写或小写.
void *memmove(void *destin,void *source,unsigned n)
从source复制字节到destin
void *memcpy(void *destin,void *source,unsigned n)
从source复制字节到destin
void *memset(void *s,char ch,unsigned n)
将s的所有字节置于字节ch中.s数组的长度由n给出.
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.9 stdarg.h
Stdarg.h头文件提供了访问可变参数表 语法概要
#define #define
typedef ... va_list;
va_start(va_list ap,type LastFixedParm) ... va_arg(va_list ap,type)...
void void
va_end(va_list ap); va_copy(va_list dest,va_list src);
#include<stdarg.h>
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.9 stdarg.h
stdarg.h中定义的宏、函数和类型的含义 Va_list 这种类型声明局部状态变量,用于遍历参数。
Va_start 这个宏初始化状态变量ap,要先调用之后才能调用.将ap中的 内部指针设置成指向传入函数的第一个可变参数。
Va_arg 这个宏返回参数表中下一个参数的值,将内部参数指针(在ap中 )移到下一个参数(如有)。
Va_end 这个函数或宏在用va_arg读取所有参数之后调用。
Va_copy (C99)这个宏在dest中复制src的当前状态,在参数表中生成第
二个指针。然后可以独立对src与dest采用va_arg。
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.9 stdarg.h
编写可变个数参数的函数
#include “printargs.h”
int arg_types[] =(INTARG,DBLARG,INTARG,DBLARG,0); int main()
{
printargs(&ar9_types[0],l,2.0,3,4.0);
return 0; }
printargs的声明和整数类型指定符的值放在文件printargs.h中。
/* file printargs.h;Standard C。*/ #include<stdarg.h>
#define INTARG 1 /* codes used in argtypep[]*/ #define DBLARG 2
......
void printargs(int *argtypep,...);
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.9 stdarg.h
标准C语言中printargs的相应定义如下: #include<stdio.h>
#include “printargs.h”
void printargs( int*argtypep,...) /* Standard C */ {
va_list ap;
int argtype; va_start(ap,argtypep);
while (( argtype = *argtypep++) != 0) {
} }/*while*/
switch(argtype) {
case TNTARG: printf(”int:%d\n”,va_arg(ap,int)); break;
case DBLARG: printf(“double:%f\n“,va_arg(ap,double)); break;
va_end(ap);
嵌入式家园 www.embedclub.com
}git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.10 setjmp.h
语法概要
#include<setjmp.h>
typedef ...... jmp_buf;
int setjmp(Jmp_buf env);
void longJmp(jmp_buf env,int status)
setjmp与longjmp函数实现
非本地跳转
处理异常
例外情形
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.10 setjmp.h
jmp_buf
数组类型
Setjmp
env是个由实现定义的数组 返回0
Longjmp
env是个由实现定义的数组 返回status
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.10 setjmp.h
例
#include<setjmp.h> Imp_buf ErrorEnv; int guard(void)
/* Return 0 if successfult else longjmp code.*/ {
}
int status = setjmp(ErrorEnv); if(status!=0) return status; /*error*/ process();
return 0;
int process(void) {...
if(error_happened)longjmp(ErrorEnv,error_code); }
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.11 signal.h
语法概要
#include <signal.h>
#define SIG_IGN #define SIG_DFL #define SIG_ERR #define SIGxxxx......
void(*signal(int sig,void(*func)(int)))(int); int raise(int sig);
typedef ... sig_atomic_t;
/* Non—Standard extensionst */
int kill(int pid,intsig);
int (*ssignal(int softsig,int(*func)(int)))(int);
int gsignal(int softsig);
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitvoid peignal(int sig,char* prefix);
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.11 signal.h
运用特点
信号是(潜在的)异步事件 信号的触发可以通过计算机的错误探测机制、用户程序中的kill或raise函数以及程
序外部的操作
用法:
信号处理器是个用户函数
void my_handler(int the_signal){...} SIG_IGN -signal(sig,SIG_IGN) SIG_DFL -signal(sig, SIG_DFL)
raise或gsignal函数在当前进程中发出指定的信号(或软件 信号)
kill函数使特定进程中发出指定的信号 嵌入式家园 www.embedclub.com
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.11 signal.h
运用实例
void new_handler(int sig){...} void(*old_handler)();
/*Set new handler,saving old handler*/ old_handler = signal(sig, &new_handler); if(old_handler == SIG_ERR)
fprintf(”stderr,”?Could.t establish new handler.\n”);
/* store old handler*/ if(signal(sig,old_handler)==SIG_ERR)
fprintf(“stderr,”?Could。t put back old handler.\n”);
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.3.11 signal.h
信号处理注意事项
如果信号是由raise或gsignal发出的,则这些函数返回其调用者。 如果信号是由abort发出的,则标准c语言程序终止。其他实现可能返回abort
的调用者。
如果处理的信号是SIGFPE或另一实现定义的计算信号,则返回时的行为是未 定义的。
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.4 标准库应用总结
编写参数数目可变的函数 判断字符 标准C的异常处理机制 对内存进行操作的标准库函数
C语言日期操作 malloc()、calloc()、realloc() NULL和NUL的区别 非格式化输入输出函数
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.4.1编写参数数目可变的函数 利用stdarg.h
例:
printf(" Hello, world! \n" ); /* no more arguments */
printf("%s\n" , "Hello, world!"); /* one more string argument */ printf("%s, %s\n" , "Hello" , "world!"); /* two more string arguments */ printf("%s, %d\n", "Hello", 42); /* one string, one int */
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.4.2 标准C的异常处理机制
绝对终止 条件结束 非局部goto 信号(Signals) 公共变量
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.4.2.1 绝对终止
调用stdlib.h
abort: 粗鲁地结束程序 exit: 文明地结束程
两者区别
abort立即结束程序 ,不保存数据 exit保存数据,执行客户用atexit注册的清除代码
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.4.2.1 绝对终止 例
#include <stdio.h>
#include <stdlib.h>
static void atexit_handler_1(void)
{
printf("within 'atexit_handler_1'\n");
结果
}
static void atexit_handler_2(void)
within 'atexit_handler_2' within 'atexit_handler_1' 并返回退出码给调用环境.
{
printf("within 'atexit_handler_2'\n");
}
int main(void) {
atexit(atexit_handler_1);
atexit(atexit_handler_2);
exit(EXIT_SUCCESS);
printf("this line should never appear\n");
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
return 0; }
2.4.2.2 条件结束 <assert.h> 中的assert
#define assert(condition) _assert((condition), #condition, __FILE__, __LINE__)
printf函数 调用abort终止程序
自定义assert函数 例:
void _assert(int test, char const *test_image, char const *file, int line) {
} }
if (!test) {
printf("Assertion failed: %s, file %s, line %d\n", test_image, file, line); abort();
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.4.2.3 非局部goto
<setjmp.h > 中的setjmp与longjmp
特点
可以goto到任何地方 在程序的任意地方控制它
操作特点
jmp_buf内容:程序位置指针、堆栈与框架指针,寄存器与内存值 setjmp(j)设置goto指针
setjmp可以标记相应的异常处理过程
longjmp来引发终止异常
longjmp(j, r)来goto到对象j指定的地方
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.4.2.3 非局部goto 操作实例
#include <setjmp.h> #include <stdio.h> jmp_buf j;
void raise_exception(void) {
int main(void) {
printf("exception raised\n");
printf("'setjmp' is initializing 'j'\n"); raise_exception();//恢复上下文 printf("this line should never appear\n");
longjmp(j, 1);
} else {
/* jump到异常处理过程 */
printf("this line should never appear\n"); }
printf("'setjmp' was just jumped into\n");
运行结果
/* 异常处理过程 */ }
运行结果
return 0; }
'setjmp' is initializing 'j'
'setjmp' is initializing 'j'
exception raised
exception raised
setjmp' was just jumped into
setjmp' was just jumped into
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
if (setjmp(j) == 0) {
2.4.2.4 信号(Signals)
<signal.h > 中的raise与signal
实例
raise来引发信号,并进入到相应的处理过程
signal两种安装指定处理方法:
* signal(SIGxxx, SIG_DFL),//使用系统默认的处理方法. * signal(SIGxxx, SIG_IGN), //告诉系统忽略信号。
void handler(int signal_value); void f(void)
{
}
signal(SIGFPE, handler); /* 注册处理过程*/
/* ... */
raise(SIGFPE); /* 通过 'SIGFPE'来调用处理过程 */
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.4.3 对内存进行操作的标准库函数
memmove() 与memcpy() 内存copy
Memmove 考虑到相互覆盖 memcpy 速度比 memmove 快
例: 将buf从"RIGHT"改为“RIGRIGHT”
static char buf[] ={'R','I','G','H','T','\0','-','-','-'}; Int main()
{
int i;
for (i = 0; i<6; ++i) {
buf[i + 3] = buf[i]; }
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
}
2.4.4 对内存进行操作的标准库函数
memcmp() 与strncmp() memcmp遇到NULL字符时不会结束 memcmp()函数不能用来比较结构的值
例: 结构体比较 struct foo{
short s; long l;
} 分析(32位系统环境)
struct foo byte[0] s的低位字节 struct foo byte[0] s的低位字节
struct foo byte[1] s的高位字节 struct foo byte[1] s的高位字节
struct foo byte[2] 无用信息(使l从一个long类型边界开始) struct foo byte[2] 无用信息(使l从一个long类型边界开始)
struct foo byte[3] 无用信息(使l从一个long类型边界开始) struct foo byte[3] 无用信息(使l从一个long类型边界开始)
struct foo byte[4] l的最低位字节 struct foo byte[4] l的最低位字节
struct foo byte[5] l的次低位字节 struct foo byte[5] l的次低位字节
struct foo byte[6] l的次高位字节 struct foo byte[6] l的次高位字节
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitstruct foo byte[7] 1的最高位字节
struct foo byte[7] 1的最高位字节 git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.4.4 对内存进行操作的标准库函数
strcpy() () 与memcpy () strcpy()函数只能拷贝字符串,遇到NULL字符时结束 memcpy()函数可以拷贝任意类型的数据,指定字节数
使用规则
拷贝字符串时,通常都使用strcpy()函数 在拷贝其它数据时,通常都使用memcpy()函数。
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.4.4 对内存进行操作的标准库函数 例
#include <stdio. h> #include <string. h>
typedef struct cust_str {
int id ;
char last_name [20] ; char first_name[l5];
} CUSTREC;
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.4.4 对内存进行操作的标准库函数
例
void main (void) {
}
d嵌est入_c式ust家. id园, dewstw_cwu.setm. fibrsetd_cnlaumbe.c, odemst_cust. last_name) ; 嵌入式家园 www.embedclub.com
char * src_string = "This is the source string" ; char dest_string[50];
CUSTREC src_cust;
CUSTREC dest_cust;
printf("Hello! I'm going to copy src_string into dest_string!\n"); printf("Done! dest_string is: %s\n" , strcpy(dest_string, src_string)) ; printf("Encore! Let's copy one CUSTREC to another. \n") ;
prinft("I'll copy src_cust into dest_cust. \n");
/ * First, intialize the src_cust data members. * /
src_cust. id = 1 ;
strcpy(src_cust. last_name, "Strahan");
strcpy(src_cust. first_name, "Troy");
memcpy(&dest_cust, &src_cust, sizeof(CUSTREC)); printf("Done! I just copied customer number # %d (%s %s). " ,
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.4.4.1 日期概述
Coordinated Universal Time(UTC)世界标准时间
Calendar Time:日历时间 epoch:时间点
clock tick:时钟计时单元
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.4.4.2 计时 C中的计时函数是clock()
lock_t clock( void )
#define CLOCKS_PER_SEC ((clock_t)1000)
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.4.4.2 计时 实例:机器运行一个循环或者处理其它事件到底花了多少时间
#i nclude “stdio.h” #i nclude “stdlib.h” #i nclude “time.h” int main( void )
{
long i = 10000000L; clock_t start, finish; double duration;
/* 测量一个事件持续的时间*/
printf( "Time to do %ld empty loops is ", i );
start = clock();
while( i- -);
finish = clock();
duration = (double)(finish - start) / CLOCKS_PER_SEC;
printf( "%f seconds\n", duration );
system("pause");
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
}
2.4.4.2 计时
实例:获得日历时间 time_t time(time_t * timer); 代码分析
#include "time.h" #include "stdio.h" int main(void)
{
结果:The Calendar Time now is 1122707619 结果:The Calendar Time now is 1122707619
}
struct tm *ptr;
time_t lt;
lt =time(NULL);
printf("The Calendar Time now is %d\n",lt); return 0;
即从1970年1月1日0时0分0秒到此时的秒数。 即从1970年1月1日0时0分0秒到此时的秒数。
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.4.4.2 计时
实例:获得日期和时间
struct tm * gmtime(const time_t *timer);
}
获得的世界标准时间是2005年7月30日7点18分20秒 struct tm * localtime(const time_t * timer);
获得的本地时间会比时间标准时间晚8个小时 代码分析
#include "time.h" #include "stdio.h" int main(void)
{
结果:
struct tm *local;
time_t t;
t=time(NULL);
local=localtime(&t);
printf("Local hour is: %d\n",local->tm_hour); local=gmtime(&t);
Local hour is: 15
printf("UTC hour is: %d\n",local->tm_hour);
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitreturn 0;
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
结果:
Local hour is: 15
UTC hour is: 7
UTC hour is: 7
2.4.4.2 计时 固定的时间格式
格式:
星期几 月份 日期 时:分:秒 年\n\0 例如:Wed Jan 02 02:03:55 1980\n\0
char * asctime(const struct tm * timeptr); 通过tm结构来生成具有固定格式的保存时间信息的字符串 把tm结构对象中的各个域填到时间字符串的相应位置
char * ctime(const time_t *timer);
通过日历时间来生成时间字符串 先参照本地的时间设置 再把日历时间转化为本地时间 然后再生成格式化后的字符串。
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.4.5 malloc()、calloc()、realloc() malloc()
修改一个原先已经分配的内存块的大小
分配特点
增加
缩小
内存原先的内容依然保留
新增加的内存添加到原先内存块的后面
如果原先的内存块无法改变大小,分配另外一块正确大小的内存,并把原先
那块内存的内容复制到新的块上
内存块尾部的部分内存便被拿掉
剩余部分内存的原先内容依然保留
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.4.5 malloc()、calloc()、realloc()
realloc()
有一个参数,分配的内存空间的大小 语法:void *malloc(size_t size) 不能初始化所分配的内存空间 可能有遗留各种各样的数据 返回一个对象
calloc()
有两个参数,分别为元素的数目和每个元素的大小
语法:void *calloc(size_t numElements,size_t sizeOfElement); 能初始化所分配的内存空间 分配的内存空间中的每一位都初始化为零 返回一个由某种对象组成的数组
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.4.6 NULL和NUL的区别
NULL
NUL
定义空指针宏 NULL可以被定义为(void *)0
ASCII字符集中第一个字符的名称,对应于一个零值 NUL可以被定义为'\0'
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
2.5 标准库应用总结
编写参数数目可变的函数 判断字符 标准C的异常处理机制 对内存进行操作的标准库函数
标准C语言运算符宏 串拷贝与内存拷贝 C语言日期操作 非格式化输入输出函数
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
阶段小节
如何编写一个可变参数的函数
C语言库中的日期函数的具体实例操作 内存和字符串函数库的实例应用和分析 格式化输入和输出操作
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
本章结构
C标准语言库概要和应用 C标准语言库概要和应用
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
标准语言库概述
标准语言库概述
标准C语言函数 标准C语言函数
简单讲述了C语言库和C++ 之间的特性
主要库文件 主要库文件
本节着重讲述在C语言编程 中常需用到的标准库函数
标准库应用总结
标准库应用总结
深入讲述标准语言库的具体
应用
本节主要讲述标准语言的
发展历史和特性
实验1 题目
从文件file.txt中读出所有内容,并计算出文件中有多少个字母,有多少数 字,有多少个标点符号。注意在操作过程要用malloc来分配内存空间;
实验目的
考察对文件的读操作;
练习判断字符库中的函数用法;
考察对内存函数的操作和字符串函数的应用
实验分析
计算出文件字符的数量,申请对应大小的空间;
读出文件中的内容,并拷贝写入到内存空间中;
统计分析内存空间的字符情况;
实验结果
熟悉对文件的操作,同时深入理解内存和字符串的操作细节。
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
实验2
实验内容
就第一题的所得的结果,添加到文件末尾:格式为 写入时间:格式1970年1月1日0时0分0秒 字母:num 个
数字:num 个
标点:num 个 统计时间:1970年1月1日0时0分0秒 操作用时:NUM ms。
实验目的
考察对文件的写操作; 了解C语言的日期函数操作;
实验分析
通过日期函数得到当前时间;
通过文件写入函数向文件末尾添加内容;
记录数据写入完时的时间;
通过时间差函数得到操作所用的时间;
实验结果
熟悉文件的操作的定位,同时深入体验C语言日期操作函数 。
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.gitgit@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git