⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 数据类型转换.01

📁 经典C教程,带所有ANSI C的库函数说明及例子
💻 01
📖 第 1 页 / 共 3 页
字号:
函数返回一个double型数。然后把函数名quad_poly 赋给这个指针。
通过fx(x)引用这个函数,取得函数的返回值。
    有时候,程序中要用到多个函数,这些函数有相同的参数要求和
相同的返回值类型。但这些函数不是同时都要用到,而是根据不同的
情况每次仅调用其中的一个。比较笨拙的办法就是用switch语句去实
现,虽然也还清楚,但程序显得冗长。用函数指针则显得精练多了,
如下面的例子所示:    #include<stdio.h>
    #include<conio.h>
    #include<math.h>
    #define MAX 3
    main()
    {
	double x;
	const double delta=1.0;
	const double first=0.0;
	const double last=1.0;
	double (*fx[MAX])();
	int i;
	char ch;
	double quad_poly(double);
	fx[0]=quad_poly;
	fx[1]=sqrt;
	fx[2]=log;
	for(i=0;i<MAX;i++){
	    x=first;
	    while(x<=last){
		printf("f(%1f)=%1f\n",x,fx[i](x));
		x+=delta;
	    }
	    printf("press any key to continue");
	    ch=getche();
	    clrscr();
	}
    }
    double quad_poly(double x)
    {
	double a=1.0,b=-3.0,c=5.0;
	return ((x*a)*x+b)*x+c;
    }
    在这个例子里,有三个数学函数 quad_poly, sqrt和log,它们
都只要一个dboule型参数,都返回一个double型数。程序中通过语句
double (*fx[MAX])()说明fx是函数指针数组,每一个函数都返回
double型数。然后用三个函数的名字初始化这个函数指针数组,通过
fx[i](x)在每次循环中各引用一个不同的函数,取得函数的返回值。
    第2 种用途是通过函数指针,把一个函数作为参数传递给另一个
函数,请看下面这个例子:    #include<stdio.h>
    main()
    {
	double x;
	const double delta=0.01;
	const double first=0.0;
	const double last=10.0;
	double (*fx)();
	double quad_poly(double);
	double find_largest(double,double,double,double (*fx)());
	fx=quad_poly;
	printf("The largest value in the range %1f->%1f",first,last);
	printf("is %1f\n",find_largest(first,last,delta,fx));
    }
    double quad_poly(double x)
    {
	double a=1.0,b=-3.0,c=5.0;
	return ((x*a)*x+b)*x+c;
    }
    double find_largest(double a,double b,double step,double (*fx)())
    {
	double x=a,big=(*fx)(a);
	while(x<=b){
	    if(big<(*fx)())
		big=(*fx)(x);
	    x+=step;
	}
	return big;
    }
    在这个例子里,函数quad_poly计算(a*x3+b*x+c)的值,参数x和
返回值教师double型数。函数find_largest根据某一计算法则求出在
某一范围内(某一步长)的最大值。不但范围和步长是由调用参数指定,
计算法则也是由调用参数指定,所有的参数返回值都是double型数。
主函数main调用find_largest求最大值,通过函数指针把函数
quad_poly人微言轻参数传给find_largest。段与偏移量
    8086和80286的寄存器都是8位或16位的,而8086以及工作于实地
址方式下的80286/80386的地址空间却是20 位的。这样在寻找下一条
将执行的指令时以及当用寄存器间接寻址内存中某一数据时,16位的
指针寄存器和地址寄存器却不足以存下20位地址。为了解决这个问题,
便把20位地址分为两部分,分别称为段地址和偏移量。段地址可以是
任一16字节边界处,即段地址的末4位一定是0,不需要保存,只把高
16位存入段寄存器中。偏移量也是16位的,一方面便于寄存器间接寻
址,但另一方面也限制了每段不能超过64K 字节。考虑到程序和数据
的寻址一般都是连续的,故这种设计还是合理的。
    在80X86微机中,总是有4个16位段寄存器:CS,DS,SS,ES。在
Turbo C编译产生的目标码中,一般只用到了其中的3个寄存器,CS用
来存放码的段地址,DS用来存放全局变量和静态变量所在段的段地址,
SS用来存放局部变量,参数(以及其它属于某一个函数的信息)所在段
的段地址。在Microsoft C 6.0中,ES用来存放基指针的段地址。 如
果需要,在Turbo C 中,程序员可以通过伪变量_DS、_CS、_SS、_ES
取得这些段寄存器的值。
    如果程序的码、数据和堆栈分别都不超过连续64K 字节,则在程
序的整修执行过程中,CS、DS和SS寄存器的值可以不变,仅仅通过对
单字偏移量的操作就可以寻址到所有的码和变量,这样速度比较快。
如果码或数据不能在边续64K 字节内放下,则必须用双字的段:偏移
量来寻址,但速度也就变慢。在所有程序中,堆栈的操作都较频繁,
所以都禁止使用双字的寻址方法,并限制堆栈不能超过64K 字节,即
不超过一段,尽管有时各个程序模块使用自己独立的堆栈。
    有时,我们知道了某一个存储单元的段地址,也知道它的偏移量,
也知道它的偏移量,但这个段地址和偏移量并没有构成一个远指针。
Turbo C中提供了如下4 个宏,使得可以从这个内存单元中读(或往这
个内存单元中写)1个字节(或1个整数)。
    char peekb(unsigned segment,unsigned offset)
    int   peek(unsigned segment,unsigned offset)
    void pokeb(unsigned segment,unsigned offset,char value)
    void  poke(unsigned segment,unsigned offset,int value)
    下面是从ROM的地址FFFF:000E中读1个字节的例子,这个字节实
际上就是微机类型的标志字节。
/*    #include<general.h>*/
    #include <dos.h>
    void main(){
        printf("PC model=hex%x",( char ) peekb(0xffff,0x000e));
    }
    这4个宏以及下面将介绍的3个宏的定义都在头文件dos.h 中,但
在头文件general.h中包含有#include<dos.h>这样一行,所以在上面
这个例子中只写了#include<general.h>。因为下面经常要用到
general.h,故单独把它列出来。
    /* general.h */
    #include<conio.h>
    #include<dos.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<time.h>
    #define boolean int
    #define TRUE 1
    #define FALSE 0
    #define BLANK ''
    #define CR 13
    #define beep putchar('\a')
    #define newline putchar('\n')
    #define EMPTYSTR ""
    #define FARNULL (void far *)NULL
    #define INTA00 0x20
    #define EOI 0x20
    #define strempty(s) (*(s)==0)
    boolean strequalsf(char *s,char *t,char **ps,char **pt);
    boolean strequalsb(char *s,char *t,char **pm,char **pn);
    #define strchrf strchr
    char *strchrb(char *s,char *p,char c);
    #define strpbrkf strpbrk
    char *strstrf(char *s,char *t);
    char *strstrb(char *s,char *t);
    char *stralloc(char ch,unsigned N);
    char *strsubst(char *s,char *a,char *b);
    char *strltoa(long N,char *s,int radix);
    char *strshrte(double x,char *s);
    char *strultoe(unsigned long N);
    char *strtomoney(double x,int code);
    char *strtime(char *timestr,const struct tm *t,
	          boolean twentyfourhours,char separator);
    char *strday(char *datestr,const struct tm *t,int format,
	         char separator);
    #define leap(year) ((year)%4==0 && ((year)%100!=0 || (year)%400==0))
    int dayofyear(int day,int month,int leapyear);
    long gregorian(int day,int month,int year);
    #define weekday(day,month,year) (gregorian(day,month,year)+5)%7
    unsigned envseg(unsigned PSP);
    char *progname(unsigned PSP);
    void memrymap(void);
    unsigned extmem(vid);
    void ctryinfo(unsigned code,struct country *c);
    void peep(void);
    int retorisr(int N,char *id);
    int rstorint(char *id);
    有时,我们知道了段地址和偏移量,需要把它们合并成一个远指
针。Turbo C的宏MK_FP可以用来做这件事。
    (void far *)MK_FP(unsgined segment,unsigned offset)    Turbo C 的另外两个宏正好做相反的事情,它们从一个远指针中
分解出段地址和偏移量。
    (unsigned)FP_SEG(void far *p)
    (unsigned)FP_OFF(void far *p)
    Turbo C中还提供了其它一些手段,使得可以像汇编语言中一样,
知道了偏移量和段地址在哪一个段寄存器,就可以用如下这样的程序
来存取某一内存单元:
    char peekb(unsigned segment,unsigned offset)
    {
        _ES=segment;
        return *(unsigned char _es *)offset;
    }    这个程序中用伪变量_ES把参数segment(段地址)存放到寄存器ES
中,用修饰符_es把参数offset(偏移量)强制转换为指向字符的指针,
但这个指针是相对于寄存器ES而不是缺省的DS,然后再去取1个字节。
由于这个程序(函数)的名字也是peekb,与Turbo C提供的宏同名,如
果要用用户定义的peekb,则在源程序中不应包含头文件dos.h。

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -