C语言-C程序组成

    一个c语言项目工程由多个 .c 和 .h文件组成
    .c  源码文件
    .h  头文件

1,.c文件组成

一般来说,.c文件由以下部分组成

(1)头文件包含部分

        #include<头文件名字> //包含系统头文件

        或

         #include"头文件名字" //包含自己写的头文件

    作用就是把 该头文件在 这个位置展开-》就是把这个头文件的内容复制粘贴到这个位置
​
    这里有一个问题:包含头文件的时候,只写了文件的名字,没有写文件的路径,怎么找到的?
    每个系统都有“环境变量”,我们需要设置它,指定编译器、头文件、库文件等重要文件的路径(位置)
​
    <> 和 "" 的具体区别
    <>中的头文件 会去 "环境变量"中指定路径去找。
    ""中的头文件 会先在 当前工程指定的路径(如果没有指定,默认就是当前文件夹)下去找,如果没有
        再去 "环境变量"中指定路径去找。如果都不存在,则报错
​
(2) 宏定义部分
    宏定义语法:
        不带参数
            #define 宏名 表达式
            作用是:在编译(预处理)时刻进行替换,用 表达式 替换 代码中出现的 宏名
​
            如:
                #define Pi 3.14
                在编译(预处理)的时候,文件中凡是有 Pi的地方,全部用 3.14去替换
        带参数
            #define 宏名(参数) (表达式)
​
            如:
                #define MAX(a,b) (a>b?a:b)
​
            int x=10;
            int y=20;
            int c;
            c = MAX(x,y); //替换之后: c= (x>y?x:y);
​
            c = MAX(x+1,y-1) + 1;//替换之后: c = (x+1>y-1?x+1:y-1) + 1;
​
            c = MAX(x&10,y/3) ; //替换之后: c = (x&10>y/3?x&10:y/3);
            本来的意思是:求 x&10 和 y/3中的最大值并赋值给c ,-》 c = 10
            替换之后的结果: c = 6,原因是 >的优先级 高于 &
​
            所以:定义宏的时候,不仅整个表达式需要加括号,而且每个参数都需要加括号
            -》
            #define MAX(a,b) ((a)>(b)?(a):(b))
​
            c = MAX(x&10,y/3) ;  //替换之后:
            c = ((x&10)>(y/3)?(x&10):(y/3)) ;
​
    练习:
        int x=10;
        int y=5;
​
        #define SQR(x,y) ((x/y)*(x/y))
​
        求  SQR(x/y,x*y) 的值  0
​
        ((x/y/x*y)*(x/y/x*y))
​
    即使每个参数都加了括号,有些特殊情况,还是会有问题:
        替换宏的时候,会多次执行参数表达式
    例如:
        int a = 8;
        int b = 9;
​
        int x = MAX(a++,b++);//本来的意思是求 a++和b++这两个表达式的最大值并赋值给x
                            //x = 9
​
        但事实上:
        int x = ((a++)>(b++)?(a++):(b++)) ;
        x = 10;
        怎么改进??
        #define MAX(a,b) ({  \
            typeof(a) aa = a;\
            typeof(b) bb = b;\
            (aa)>(bb)?(aa):(bb);\
        })
​
        int x = MAX(a++,b++);
        替换之后:
        int x = ({  \
            typeof(a++) aa = a++;\
            typeof(b++) bb = b++;\
            (aa)>(bb)?(aa):(bb);\
        })
​
        typeof(a++) 只是求a++的类型,并不会进行计算
​
宏和函数的区别:
    调用函数需要额外的开销(比如说为形参分配内存,现场保护和现场恢复..)
    但是宏不需要开销,因为是在编译时刻直接替换(运行时刻根本就没有宏了)
​
    宏只适用于简单的功能,稍微复杂的功能肯定还是得写函数

(3) 声明部分 (如果有.h文件的话,这部分应该写在.h文件中)
    声明:就是告诉编译器这是个什么东西
        函数声明
        结构体/共用体/枚举等类型声明
        外部变量的声明
​
    函数声明:
        返回值类型 函数名(形参1类型 形参1名,形参2类型 形参2名 ...);
        或者
        返回值类型 函数名(形参1类型 ,形参2类型 ...);
​
    类型声明:
        struct student
        {
            int id;
            char name[20];
            double score;
            //....
        };
        声明了一个新的类型 : struct student
​
        typedef struct student Student;
        声明了一个类型 Student
        .....
​
    外部变量的声明
        什么叫做外部变量?定义在这个项目工程的其它文件中的未被 static修饰的全局变量(不是定义在当前文件)
​
        声明语法:
            extern 类型 变量名;
​
        例如:这个项目工程有2个.c 文件
        1.c                             2.c 
        int data = 100;//全局           想要访问 data,必须要进行外部声明:
                                        extern int data;//告诉编译器这是定义在别的文件中的一个变量
                                        //声明之后就可以在 2.c文件中访问 data了
​
    一个工程中如果有多个.c文件,怎么编译?
    gcc .c文件名列表
​
(4) 全局变量的定义 
    类型 变量名;
    类型 变量名=初始值;
​
    定义会为变量分配内存空间
    声明不会,声明只是告诉编译器这个东西是什么
​
(5) 函数定义
    返回值类型 函数名(形参1类型 形参1名,形参2类型 形参2名 ...)
    {
        .....
    }
​
    int main()
    {
        ....
    }
​
    void test1()
    {
        .....
    }
​
    功能性语句必须要写在函数内部(除各种定义和声明语句外)!!!!
​
    条件编译:有选择的进行编译
    (1)
    #if 表达式
    ...我们写的代码.....    //如果 #if 后面的表达式成立,这段代码就会编译
                            //如果 #if 后面的表达式不成立,这段代码就不会编译
    #endif
​
    ------------------------------
    (2)
    #if 表达式
    ...我们写的代码1.....
    #else
    ...我们写的代码2.....
    #endif
​
    如果#if后面的表达式成立,只会编译 代码1
    如果#if后面的表达式不成立,只会编译 代码2
​
    -----------------------------------
    (3)
    #ifdef XXX     //( #ifdef : if define)
    ...我们写的代码.....   //如果前面定义了 XXX这个宏,那么就会编译此处的代码
                        //如果前面没有定义了 XXX这个宏,那么就不会编译此处的代码
                        //判断条件是: 有没有这个宏,而不是这个宏的内容
    #endif  
    ---------------------------
    (4)
    #ifndef XXX     //( #ifndef : if not define)
    ...我们写的代码.....   //如果前面没有定义 XXX这个宏,那么就会编译此处的代码
                        //如果前面定义了 XXX这个宏,那么就不会编译此处的代码
                        //判断条件是: 有没有这个宏,而不是这个宏的内容
    #endif  

2, .h文件

一个简单的项目可以没有 .h文件

但是稍微复杂一点的项目 必须要写 .h文件

为啥需要写 .h文件 ?
​
在进行项目开发时,需要把功能模块化:一个功能是一个模块,一个模块对应着一个 .c和.h文件 
这样便于多人共同开发(一个人负责若干个模块,一个人负责若干个.c和.h文件的编写);
​
张三:负责A功能     A.c     -> 写了很多关于A功能的函数
李四:负责B功能     B.c     -> 写了很多关于B功能的函数
王五:负责C功能     C.c     -> 写了很多关于C功能的函数
​
主函数单独写在一个文件中,不写在功能模块.c文件中 
​
这些功能之间不是完全独立的,意味着各个功能模块间需要相互调用函数,使用其它模块的自定义数据类型....
​
张三要调用李四的函数,怎么办? 需要问李四这个函数长什么样(名字是什么,参数是什么,返回值是什么...)
                调用前需要进行声明
王五要调用李四的函数,怎么办? 需要问李四这个函数长什么样(名字是什么,参数是什么,返回值是什么...)
                调用前需要进行声明
......
​
效率太低 -》 
每个.c文件对应一个 .h文件 ,.h文件中写各种声明语句 :类型的声明 、函数的声明、外部变量的声明 ...
​
有了.h文件后,A模块需要调用B模块的函数,只需要包含B模块的.h文件 。
.h文件中写各种声明语句 :类型的声明 、函数的声明(包括注释)、外部变量的声明.....
根据 .c文件来写,.c文件中包含了哪些东西,.h文件中就声明什么
具体的应用参考: main.c math.c math.h sort.c sort.h 

为了避免重复包含头文件(一个.c文件直接或间接包含多次同一个.h文件)的危害,.h文件应该这个写:

#ifndef __XXX_H__   //XXX是这个头文件的名字
#define __XXX_H__

头文件的内容

#endif

int a[][3] = {{1,2,3},{4,5,0}}, (*pa)[3],i;

pa = a;  -> pa = &a[0];

pa[1][i] <->  *(*(pa+1)+i) <-> *(*(&a[0]+1)+i) <-> *(a[1]+i) <-> *(&a[1][0] + i)
<-> *(&a[1][i]) <-> a[1][i]

for(i=0;i<3;i++)
{
    if(i<2)
        pa[1][i]-1;
    else
        pa[1][i] = 1;
}
作业:
    声明一个复数类型
    struct complex
    {
        int real;
        int imag;
    };

    复数基本操作有 加减乘除,写函数实现

    要求:
        .c    .h

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
C语言的词法分析程序是用来对源程序进行词法分析的工具。词法分析的目的是将源程序按照语法规则划分成一个个单词,包括关键字、自定义标识符、整数、界符和运算符。关键字是预定义的特殊单词,如main、if、else、for、while和int。自定义标识符是除关键字外的其他标识符。整数是无符号的数字。界符是一些特殊符号,如{ } ( ) , ;。运算符则包括= - * / < <= > >= == !=。为了实现词法分析,可以使用NFA(非确定有穷自动机)和DFA(确定有穷自动机)的方法构造词法分析程序。这个程序可以对输入的字符串流进行词法分析,识别出关键字、运算符和定界符,并识别其他单词为标识符(id)和整型常数(num)。词法分析程序的输出形式是按照二元组单词串的形式输出。构造一个小C语言的词法分析程序可以使用正规式来定义词法规则。例如,标识符可以由字母开头,后面可以是字母或数字,整数由数字组成。词法分析程序将按照这些规则来识别不同的单词类型。在词法分析程序中,还可以使用产生式来定义语法规则,如因子可以是标识符、无符号整数或算术表达式等。如果您想使用Python编写一个小C语言的词法分析程序,您可以根据上述的词法规则和语法规则来设计程序的逻辑,使用正则表达式来匹配不同的单词类型,并将其输出为二元组单词串的形式。在程序中,您可以使用字符串处理和正则表达式库来辅助实现词法分析的功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [A - 小C语言--词法分析程序](https://blog.csdn.net/qq_46452300/article/details/123394158)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [【编译原理】使用python构造高级语言c语言的词法分析程序,模拟词法分析过程](https://blog.csdn.net/The_Handsome_Sir/article/details/124392414)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值