zoukankan      html  css  js  c++  java
  • C语言知识总结(5)

    预处理指令

    C语言提供的预处理指令主要有:宏定义、文件包含、条件编译

    宏定义

    不带参数的宏定义

    1>一般形式

    #define 宏名 字符串

     比如#define A 10

    2>作用

    它的作用是在编译预处理时,将源程序中所有"宏名"替换成右边的"字符串",常用来定义常量。

    3>使用习惯及注意

    • 宏名一般用大写字母,以便与变量名区别开来,但用小写也没有语法错误
    • 对程序中用双引号扩起来的字符串内的字符,不进行宏的替换操作。
    • 在编译预处理用字符串替换宏名时,不作语法检查,只是简单的字符串替换。只有在编译的时候才对已经展开宏名的源程序进行语法检查
    • 宏名的有效范围是从定义位置到文件结束。如果需要终止宏定义的作用域,可以用#undef命令
    • 定义一个宏时可以引用已经定义的宏名
    #define R  3.0
    #define PI 3.14
    #define L  2*PI*R
    #define S  PI*R*R

    带参数的宏定义

    1>一般形式:#define 宏名(参数列表) 字符串

    2>作用:在编译预处理时,将源程序中所有宏名替换成字符串,并且将 字符串中的参数 用 宏名右边参数列表 中的参数替换

    3>使用注意

    • 宏名和参数列表之间不能有空格,否则空格后面的所有字符串都作为替换的字符串
    • 带参数的宏在展开时,只作简单的字符和参数的替换,不进行任何计算操作。所以在定义宏时,一般用一个小括号括住字符串的参数。
    • 计算结果最好也用括号括起来
     1 #include <stdio.h>
     2 
     3 #define Pow(a) (a) * (a)
     4 
     5 int main(int argc, const char * argv[]) {
     6     int b = Pow(10) / Pow(2);
     7     
     8     printf("%d", b);
     9     return 0;
    10 }
    11 
    12 // int b = (10) * (10) / (2) * (2);
    13 // int b = 10 * (10 / 2) * 2  结果是100
    14 // 将上面的第3行代码改为:#define Pow(a) ( (a) * (a) )
    15 // 那么第6行被替换为: int b = ( (10) * (10) ) / ( (2) * (2) );
    16 // 结果是25

    宏定义与函数的区别

    1. 宏定义不涉及存储空间的分配、参数类型匹配、参数传递、返回值问题
    2. 函数调用在程序运行时执行,而宏替换只在编译预处理阶段进行。所以带参数的宏比函数具有更高的执行效率

    条件编译

    1>概念:在很多情况下,我们希望程序的其中一部分代码只有在满足一定条件时才进行编译,否则不参与编译(只有参与编译的代码最终才能被执行),这就是条件编译。

    2>基本用法

    #if 条件1
     ...code1...
    #elif 条件2
     ...code2...
    #else
     ...code3...
    #endif

    <1> 如果条件1成立,那么编译器就会把#if 与 #elif之间的code1代码编译进去(注意:是编译进去,不是执行,很平时用的if-else是不一样的)
    <2> 如果条件1不成立、条件2成立,那么编译器就会把#elif 与 #else之间的code2代码编译进去

    <3> 如果条件1、2都不成立,那么编译器就会把#else 与 #endif之间的code3编译进去

    <4> 注意,条件编译结束后,要在最后面加一个#endif,不然后果很严重

    <5> #if 和 #elif后面的条件一般是判断宏定义而不是判断变量,因为条件编译是在编译之前做的判断,宏定义也是编译之前定义的,而变量是在运行时才产生的、才有使用的意义

    其他用法

    1、#if defined() 和 #if !defined()的用法

    #if 和 #elif后面的条件不仅仅可以用来判断宏的值,还可以判断是否定义过某个宏。比如:

     #if defined(MAX)
        ...code...
     #endif

    如果前面已经定义过MAX这个宏,就将code编译进去。它不会管MAX的值是多少,只要定义过MAX,条件就成立。

    条件也可以取反:

     #if !defined(MAX)
        ...code...
     #endif

    如果前面没有定义过MAX这个宏,就将code编译进去。

    2、#ifdef 和 #ifndef的用法

    用法跟 #if defined() 和 #if !defined() 一样

    #ifdef MAX
        ...code...
    #endif
    
    #ifndef MAX
        ...code...
    #endif

    文件包含

    概念: 就是用#include,它可以将一个文件的全部内容拷贝另一个文件中。

    一般形式:

    1> #include <文件名>  直接到C语言库函数头文件所在的目录中寻找文件

    2> #include "文件名"  系统会先在源程序当前目录下寻找,若找不到,再到操作系统的path路径中查找,最后才到C语言库函数头文件所在目录中查找

    使用注意

    • #include指令允许嵌套包含,比如a.h包含b.h,b.h包含c.h,但是不允许递归包含,比如 a.h 包含 b.h,b.h 包含 a.h。
    • 使用#include指令可能导致多次包含同一个头文件,降低编译效率(解决方法如下)
    1 #ifndef Zhy
    2 #define Zhy
    3 // 函数的声明
    4 void test();
    5 
    6 #endif

    这样如果是第一次声明这个test函数就会先执行#ifndef Zhy,因为我们之前没用定义Zhy,所以进行宏定义#define Zhy,然后声明函数test,最后执行第6行代码。当第二次要重复声明test函数时,因为我们第一次声明函数时已经定义了Zhy所以不会再次声明test函数了,这样就防止了test函数的重复声明

    函数

    1.外部函数:如果在当前文件中定义的函数允许其他文件访问、调用,就称为外部函数。C语言规定,不允许有同名的外部函数。

    2.内部函数:如果在当前文件中定义的函数不允许其他文件访问、调用,只能在内部使用,就称为内部函数。C语言规定不同的源文件可以有同名的内部函数,并且互不干扰。

    extern与函数

    如果你想让一个函数可以被main.c访问,那么这个函数就必须是外部函数。完整的定义是要加上extern关键字。(一般都会省略)

    static与函数

    当我们想定义一个"内部函数"(也叫静态函数)时,也就是不想让其他文件访问本文件中定义的函数。这时你只需要在定义函数的时候加个static关键字即可。

    编译与链接

    所谓编译,就是单独检查每个源文件的语法是否合理,并不会检查每个源文件之间的关联关系,一个源文件编译成功就生成一个目标文件。

    所谓链接,就是检查目标文件的关联关系,将相关联的目标文件组合在一起,生成可执行文件。

    static关键字和extern关键字

    1>extern可以用来声明一个全局变量,但是不能用来定义变量

    2>默认情况下,一个全局变量是可以供多个源文件共享的,也就说,多个源文件中同名的全局变量都代表着同一个变量

    3>如果在定义全局变量的时候加上static关键字,此时static的作用在于限制该全局变量的作用域,只能在定义该全局变量的文件中才能使用,跟其他源文件中的同名变量互不干扰

    typedef

    我们可以使用typedef关键字为各种数据类型定义一个新名字(别名)。

    typedef int Zhy;

    typedef和指针

    typedef char *String;

    typedef和结构体

    // 定义一个结构体
    struct MyPoint {
        float x;
        float y;
    };
    
    // 起别名
    typedef struct MyPoint Point;
    
    int main(int argc, const char * argv[]) {
        // 定义结构体变量
        Point p;
        p.x = 10.0f;
        p.y = 20.0f;
        
        return 0;
    }

    可以简写

    typedef struct MyPoint {
        float x;
        float y;
    } Point;
    
    //
    typedef struct {
        float x;
        float y;
    } Point;

    typedef与指向结构体的指针

    #include <stdio.h>
    
    // 定义一个结构体并起别名
    typedef struct {
        float x;
        float y;
    } Point;
    
    // 起别名
    typedef Point *PP;
    
    int main(int argc, const char * argv[]) {
        // 定义结构体变量
        Point point = {10, 20};
        
        // 定义指针变量
        PP p = &point;
        
        // 利用指针变量访问结构体成员
        printf("x=%f,y=%f", p->x, p->y);
        return 0;
    }

    typedef与枚举类型

    // 定义枚举类型
    enum Season {spring, summer, autumn, winter};
    // 给枚举类型起别名
    typedef enum Season Season;
    
    int main(int argc, const char * argv[]) {
        // 定义枚举变量
        Season s = spring;
        
        return 0;
    }
    // 简写
    enum Season {spring, summer, autumn, winter} Season;
    
    enum {spring, summer, autumn, winter} Season;

    typedef与指向函数的指针

    #include <stdio.h>
    
    // 定义一个sum函数,计算a跟b的和
    int sum(int a, int b) {
        int c = a + b;
        printf("%d + %d = %d", a, b, c);
        return c;
    }
    
    typedef int (*MySum)(int, int);
    
    int main(int argc, const char * argv[]) {
        // 定义一个指向sum函数的指针变量p
        MySum p = sum;
        
        // int (*p)(int, int) = sum;
        // 利用指针变量p调用sum函数
        (*p)(4, 5);
        
        return 0;
    }

    typedef 和 #define

     1 typedef char *String1;
     2 
     3 #define String2 char *
     4 
     5 int main(int argc, const char * argv[]) {
     6     String1 str1, str2;
     7     
     8     String2 str3, str4;
     9     return 0;
    10 }

    第1行给char *起了个别名String1,第2行定义了宏String2。然后在第6、第8行定义了4个变量。

    注意:在这种情况下,只有str1、str2、str3才是指向char类型的指针变量,str4只是个char类型的变量。

  • 相关阅读:
    33.数组声明方式(var构造函数) 、检测数组类型、数组的属性(封装好的就一个length)、数组的方法
    31.this指向(写出调用链,找最近对象) this的默认绑定 隐式绑定 显示绑定(call(绑定对象) apply(绑定对象) 当括号内没放绑定对象的时候恢复默认绑定) bind
    31.
    30.函数作用域链 (GO AO 也叫词法作用域链)、 调用栈、调用栈涉及this绑定
    29.包装类(构造函数) 包装类作用及调用栈
    916. Word Subsets
    246. Strobogrammatic Number
    445. Add Two Numbers II
    2. Add Two Numbers
    341. Flatten Nested List Iterator
  • 原文地址:https://www.cnblogs.com/melodyzhy/p/4624310.html
Copyright © 2011-2022 走看看