鱼C论坛

 找回密码
 立即注册
查看: 96|回复: 0

[学习笔记] 每日一学18

[复制链接]
发表于 2024-12-14 16:21:39 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 6bingame 于 2024-12-14 16:21 编辑

编译于预处理指令3


文件包含

文件包含指令的功能是把指定的文件插入该指令行位置取代该指令行,从而把指定的文件和当前的源程序文件连成一个源文件。在程序设计中,文件包含是很有用的。一个大的程序可以分为多个模块,有多个程序员分别编程。有些公用的符号产量或宏定义等可单独组成一个文件,在其他文件的开头用包含指令包含该文件即可使用。这样,可避免在每个文件开头都去书写那些公用部分,从而节省时间,并减少出错。

文件包含一般形式:

#include "文件名"

或者

#include <文件名>


例题1:宏定义和文件包含
#include<stdio.h>

#include "common.h"     //包含头文件

int main()
{
    int radius;

    float circule;

    printf("请输入圆半径:");

    scanf(PD,&radius);

    circule=2*PI*radius;

    printf(PF,circule);

    printf(NEWLINE);

    return 0;
}


//新建文件2“common.h”
#define PI 3.14

#define NEWLINE "\n"

#define PD "%d"

#define PF "%f"


例题分析:
在编译这两个文件时,编译器并不是分开编译生成两个目标文件的,而是通过文件包含#include指令,把文件common.h先包含到文件myfile.h中。当然在myfile.h中还包含了标准输入输出头文件stdio.h,这些文件经过预处理指令合并在一起后,得到一个新的源程序,然后对这个新文件编译,即可得到一个“.obj”目标文件。




文件包含说明

(1)包含指令中的文件名可以用双引号括起来,也可以用尖括号括起来。
(2)一个include指令只能指定一个被包含文件,若有多个文件要包含,则需用多个include指令。
(3)文件包含允许嵌套,即在一个被包含的文件中又可以包含另一个文件,但是必须按照顺序包含。
(4)不能包含OBJ文件。文件包含是在编译前进行处理,不是在连接时进行处理的。


条件编译

在C的高级编程中,会遇到在基础学习中没有遇到过的"条件编译”。何谓"条件编译”,简单地说,就是“程序的内容指定编译的条件”。我们在写程序时,一般的情况是将源程序的所有行都参加编译,但是我们希望部分行在满足条件的情况下再进行编译,从而引出下面的几种条件编译。

条件编译形式

一般的条件编译形式:

1.#ifdef形式

#ifdef 标识符
        程序段 1
#else
        程序段 2
#endif

作用是标识符已被定义,则对程序段 1 进行编译,否则编译程序段 2。但也可以不写 #else,如下:

#ifdef 标识符
        程序段
#endif

其中的“标识符”是用#define指令定义的,程序段可以是语句,也可以是命令行。这种条件编译对于提高C程序的通用性有很大的好处。

2.#ifndef形式

#ifndef 标识符
        程序段 1
#else
        程序段 2
#endif

这种形式的条件编译与第1种形式相同,内容相反。只是ifdef替换成了ifndef,即如果标识符没有被定义过,就会编译程序段 1 ,否则就编译程序段 2。也可以不写#else,如下:

#ifndef 标识符
        程序段
#endif


例题2:使用条件编译和函数式宏定义,求两个数的大数和小数
#include<stdio.h>

#define MAX

#define MAXIMUM(x,y)(x>y)?x:y       //宏定义求大数

#define MINIMUM(x,y)(x>y)?y:x       //宏定义求小数

int main()
{
    int a=10,b=20;

    #ifdef MAX      //定义了MAX

     printf("较大的数是:%d\n",MAXIMUM(a,b));

    #else           //没有定义MAX

     printf("较小的数是:%d\n",MINIMUM(a,b));

    #endif          //结束条件编译

    #ifndef MIN     //定义了MIN

     printf("较小的数是:%d\n",MINIMUM(a,b));

    #else           //没有定义MIN

     printf("较大的数是:%d\n",MAXIMUM(a,b));

    #endif          //结束条件编译

    #undef MAX

    #ifdef MAX

     printf("较大的数是:%d\n",MAXIMUM(a,b));

    #else

     printf("较小的数是:%d\n",MINIMUM(a,b));

    #endif

    #define MIN

    #ifndef MIN

     printf("较小的数是:%d\n",MINIMUM(a,b));

    #else

    printf("较大的数是:%d\n",MAXIMUM(a,b));

    #endif

    return 0;
}


例题分析:
输出的每一行是这样的,当定义MAX时,输出较大值;但没有定义MIN时,输出较大值;当没有定义MAX,输出最小值;当定义MIN时,输出较小值。内容不复杂,只是略显多了一些。



3.#if形式

#if 表达式
        程序段 1
#else
        程序段 2
#endif

这种格式与if...else...执行过程类似。如果if表达式值为非零,就编译程序段 1,否则编译程序段 2。和前两种形式不同的是,此处需要先定义表达式,而前两种形式需要定义宏。


例题3:使用条件编译判断转换字符串为小写字母
#include<stdio.h>

#define CHARACTER 1     //定义宏CHARACTER

int main()
{
    char c,str[20]="Hello World!";

    int i=0;

    while((c=str[i])!='\0')
    {
        i++;

        #if CHARACTER

        if(c>='A'&&c<='Z')

            c=c+32;

        #else

        if(c>='a'&&c<='z')

            c=c-32;

        #endif // CHARACTER

        printf("%c",c);
    }
    printf("\n");

    return 0;
}

例题分析:
文件开头定义了符号常量CHARACTER的值为1,所以程序在条件编译时,如果检测到CHARACTER的值1,也就是非零,就会执行if语句,把大写字母转换为小写字母。如果需要把小写字母改为大写字母,不需要修改代码,仅修改宏定义即可。


调试中使用条件编译

每个大型程序都要经历内部测试Alpha版、外部测试Beta版、最终发布版,即使是发布后,应用程序还会存在bug,需要修改完善。程序开发不是一蹴而就的,需要反复地修改完善。我们修改代码,就避免不了使用调试功能,输出丰富的调试信息有助于尽快地完成程序的修复。
我们可以在程序中输出参数的值,判断什么位置出现了错误,但是如果程序调试结束在一一删除输出值的语句,工作量会比较大。因此对于大型程序,就可以在调试中使用宏。


文件嵌套包含和条件编译

由于嵌套包含文件的原因,一个头文件可能会被多次包含在一个源文件中,而使用条件指示符就可以防止这种头文件的重复处理。


assert()宏

assert()宏是在标准函数库<assert.h>头文件中定义的,称为断言。assert()宏可以让开发者在程序中插入任何表达式,用来诊断表达式的值是否为false,也就是为0。作为assert()宏参数的表达式的结果是一整个数据。


综合应用——编译与预处理指令

例题4:使用编译与预处理指令编写程序
#include<stdio.h>

#include<stdlib.h>

#include<time.h>

#define RANDOM(Number)((int)(((double)(rand())*(Number))/(RAND_MAX+1))) //生成从0到Number的伪随机数

#define TOTAL 6

#define TEST1       //定义测试输出

#define TEST2       //定义函数测试输出

#define REP         //定义重复
//声明函数
int sum(int,int);

int mul(int,int);

int dif(int,int);

int main(void)
{
    int i,funsel = 0; //选择函数序号

    int a = 10,b = 5; //初值

    int result = 0;   //结果值
//声明指向函数的指针数组
    int (*pfun[])(int,int) = {sum,mul,dif};
//执行随机函数选择
    int element_count = sizeof(pfun)/sizeof(pfun[0]);
//是否重复执行条件
#ifdef REP

    srand(1);

#else

    srand((unsigned int)time(NULL));    //随机函数播种
#endif // REP

    for(i=0;i<TOTAL;i++)
    {
        //生成随机数字,传递给pfun数组
        funsel = RANDOM(element_count);

        if(funsel>element_count-1)
        {
            printf("无效数字序号是%d\n",funsel);\

            exit(1);
        }
#ifdef TEST1

    printf("随机数序号 = %d\n",funsel);

#endif // TEST1

    result = pfun[funsel](a,b);     //调用随机函数

    printf("结果是%d\n",result);
    }
    return 0;
}
//定义函数sum
int sum(int x,int y)
{
#ifdef TEST2

    printf("sum函数的参数是%d和%d.\n",x,y);

#endif // TEST2

    return x+y;
}
//定义函数mul
int mul(int x,int y)
{
#ifdef TEST2

    printf("mul函数的参数是%d和%d.\n",x,y);

#endif // TEST2

    return x*y;
}
//定义函数dif
int dif(int x,int y)
{
#ifdef TEST2

    printf("dif函数的参数是%d和%d.\n",x,y);

#endif // TEST2

    return x-y;
}

例题分析:
本范例综合使用宏定义和条件编译,使用宏定义生成可随机数和其他的一些符号,使用条件编译完成在调试中输出结果的功能。
宏TEST1负责输出显示哪个函数被调用,宏TEST2负责输出显示生成的随机数是多少,宏REP负责是生成伪随机数海曙生成随机数。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-25 15:50

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表