• 一文教你如何高效使用C语言


    使用static关键字

    static关键字有两个作用,对于变量而言,表示该变量是一个静态变量,放在数据段中,即使函数运行结束,其变量也仍然存在。对于函数而言,表示该函数的作用域仅在该文件中,其他文件不可访问,这样有一个好处,就是当该文件仅仅只被本文件中的函数调用时,此时使用static关键字修饰可以避免其他函数因函数名相同而报错,也就是当使用该关键字修饰时,即使两个文件中的函数名完全相同,也不会报编译错误,例如下面有两个.c文件,分别是fun1.c和fun2.c。这两个文件中有函数swap,函数名完全相同。这样我们可以这样使用static关键字:

     

    //fun1.c
    static void swap(int *a,int *b)
    {
        int temp;
        temp=*a;
        *a=*b;
        *b=temp;
    }

     

    //fun2.c
    static void swap(int *a,int *b)
    {
        int temp;
        temp=*a;
        *a=*b;
        *b=temp;
    }

     

    上面两个文件中有完全一样的函数,函数只能在各自的文件中使用。

    使用const关键字

    const关键字的是constant的意思,即不变的,在C语言中作为关键字来告诉编译器变量是不可修改的。

     

    修饰变量

     

    修饰普通变量

     

    const用来修饰普通变量表示该变量的值不可修改,也就是只读。比如现在定义一个const a=10,则a的值后面将不可修改。

     

    const int a=10;  //初始化
    a=20         //错误,a的值不可修改

     

    修饰指针变量

     

    const用来修饰指针变量表示该指针的值不可修改,由于指针有两个值可以修改,一个是指针的值,即指向的位置,另一个是指针指向的位置的值,为了区分这两个值是否能修改,编译器规定采用”就近原则“,即const修饰的是离const最近的。

     

    int a=1,b=2; const int *p=&a;
    //修饰的是int *,即表示指针解引不可修改,也就是指针指向的值不能修改,等价int const *p=&a; 
    *p=10;
    //错误,p指针指向的值不可修改
    p=&b;
    //正确,没有改变p指向变量的值。
    int * const q=&a;
    //修饰的是指针q,即指针q指向的位置不可修改
    q=&b;
    //错误,q指向的位置不可修改
    *q=20;
    //正确,没有修改q指向的位置

     

    修饰数组

     

    const用来修饰数组表示该数组的所有值将不得修改,一般编译器看到一个const数组会将该数组存放在代码区中,也就是.text段,这样该数组将是只读数据。

     

    const int a[4]={1,2,3,4};
    a[1]=20; //错误,a数组所有的元素均不可修改  a数组为read only,放在代码段中

    地址对齐

    变量地址对齐

     

    地址对齐是一个非常重要的概念,现代编译器提高代码的执行速度(主要是配合cache),默认将地址都按照4字节对齐,也即是一个字对齐。我们现在看下面一个结构体:

     

    struct test
    {
        char a;
        int  b;
    }

     

    如果不了解地址对齐概念的读者可能会认为上面的结构体一共占1+4=5个字节,实际上是占8个字节,编译器会按4字节对齐,由于a变量只占一个字节,后面的b变量占4个字节,如果只给a一个字节地址,编译器会检测到b变量的地址并不是按4字节对齐的,因此编译器会默认将分配给b变量的地址向后偏移3个字节,这样b变量的地址正好的四字节对齐。

     

    #include <stdio.h>
    struct test
    {
        char a;
        int  b;
    };
    int main(int argc, char **argv)
    {
        struct test a;
        printf("size of struct test  is =%d\n",sizeof(a));
        return 0;
    }

     

    图片

     

     

    图片结构体sshshishi’jshi’ji实际结构

     

    因此在定义一个结构体时为了尽可能节约空间,必须考虑字节对齐问题。下面我们来对比两个结构体:

     

    #include <stdio.h>
    struct A{
        int    a;
        char   b;
        short  c;
    };
    struct B{
        char   b;
        int    a;
        short  c;
    };
    int main(int argc, char **argv)
    {
        struct st1;
        struct st2;
        printf("size of st1 is=%d\n",sizeof(st1));
        printf("size of st2 is=%d\n",sizeof(st2));
        return 0;
    }

     

    运行后结果如下:

     

    图片

     

    两个完全一样的结构体,仅仅只是变量存放的位置不同导致其最终所占的空间不同,这就是字节对齐带来的结果。显然结构体A要节约内存。

     

    图片

     

    指针地址对齐

     

    既然指针是变量,那是否可以对指针进行位运算呢?比如将指针的值最后一位清零:p&=(~(1)),理论上应该是可行的,因为指针本来就是变量,但实际上编译器不乐意了,它认为这样导致指针指向的地址太随意了,没有严格遵循比类型空间大小,这就导致指针没办法进行位运算操作,理论上位运算和算术运算是有等价关系的,因此也可以自己实现指针位运算,这个在C++运算符重载中可能比较方便,因此这里不详细谈指针的位运算了。

     

     

    原文链接:https://lishanwen.cn/index.php/2021/06/27/effectiveclanguage/

  • 相关阅读:
    Fluentd部署:如何监控Fluentd
    【615】国内国外经纬度坐标转换
    【614】矢量数据转栅格数据(cv2.fillPoly/cv2.polylines)
    【613】U-Net 相关
    【612】深度学习模型相关问题
    【611】keras 后端 backend 相关函数(Dice实现)
    面试官:new 关键字在 JVM 中是如何执行的?
    IntelliJ IDEA 2021.2 发布,这次要干掉 FindBugs 了!!
    Nginx 实现 10w+ 并发之 Linux 内核优化
    我们真的需要全栈开发吗?
  • 原文地址:https://www.cnblogs.com/Chary/p/16154172.html
Copyright © 2020-2023  润新知