zoukankan      html  css  js  c++  java
  • c语言编写经验逐步积累3

    版权声明:本文为CSDN博主(天才2012)原创文章。未经博主同意不得转载。 https://blog.csdn.net/gzzaigcn/article/details/27114097

    寥寥数笔。记录我的C语言盲点笔记,仅仅为以前经历过。亦有误,可交流。

    1.typedef来定义一个函数指针类型的方法,定义一个新的函数指针类型。
    :建立一个类型别名的方法非常easy,在传统的变量声明表达式里用类型名替代变量名,然后把keywordtypedef加在该语句的开头”。

    typedef int (*PFUN)(): 定义PFUN这个函数指针类型,由编译器自己主动来完毕,比方PFUN pfun;定义了一个函数指针,相似于抽象出一种新的变量类型。


    typedef unsigned short (*pTaskEventHandlerFn)( unsigned char task_id, unsigned short event );
    pTaskEventHandlerFn tasksArr[];//申明函数指针的数组

    使用typedef将一个类型名字替代原先申明时的变量名。然后类型名能够用来申明定义变量。


    2.有初始化的数组定义能够省略方括号里的数组大小。

      比如,以下的代码中数组定义为5个元素:
        int a[]={2,4,6,8,10};
      编译时必须知道数组的大小。

    通常,声明数组时方括号内的数字决定了数组的大小。

    有初始化的数组定义又省略方括号里的数组大小时。编译器统计花括号之间的元素个数,以求出数组的大小。
      比如,以下的代码产生同样的结果:
        static int a1[5]={1,2。3,4,5};
        static int a2[]={1。2。3,4,5};

    2,栈顶一般为低地址,函数入栈一般參数从右往左进行。

    3.for(a;b;c){e}运行顺序:
    先进行a, 然后是b, 运行e, 在运行c.进一步运行b,运行e,c.直到b不再满足退出循环。

    4.union数据类型。内存是重叠的,全然一样
    typedef union {
      uint32 time32;
      uint16 time16[2];
      uint8 time8[4];
    } osalTime_t;
    对time32的赋值后,訪问其它类型时依然是原来的内存。

    三个成员占领一样的数据空间。起始地址都是一样的,一旦一个成员数值变化就会出现其它成员取值也发生变化


    5.inline内联函数总结
    内联函数具有代码量小且直接编译进可运行文件里,不进行call调用,也就是在不同的文件的函数假设调用内联函数。则不同的函数都会出现该内联函数的可运行代码。
    可是,假设不反复调用的话。内联函数带来的优点就是运行更加高速,无需再call,以及函数參数的出入栈SP。保护栈帧,跳出函数,清空栈帧等各种耗时。起到高速运行的效果。故内联函数的代码量都较小。
    总之是以添加运行文件大小来获取程序运行速度的提高。

    6.(int *)0,表示指向一个整形的地址。地址值为0。即空指针所在的地方,该处一般不同意写操作,以免破坏系统。但能够读取。

    7.假设一个函数要被其它文件里函数使用,定义时加externkeyword。在没有加extern和statickeyword时。一般编译器会默认是extern类型的,因此你在其它函数里调用也能够使用。

    8.结构体之offsetof宏具体解析 ,#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER) (include/linux/stddef.h)

    9.32位机读取一个字节,实际底层的汇编做了进一步的处理。
    比方读取一个字节。实际返回的是一个32位,经过屏蔽移位取得你要的地址所在的数。写入时也一样。会先保持4字节其它字节不变,然后单独把要写入的字节做改变。由编译器依据你的数据类型来完毕实际的实现。
    32字节的读取最为高效。

    10.中断发生时,未完毕服务程序的处理时。将会忽略挂起Pending,优先级高的中断能够获取中断使用权。
    还有一个同样的中断发生,直到当前中断处理完毕,才同意再次中断进入。


    11.switch case误区。

    switch case往往对不同的命令进行分类操作,可是假设出现遇到相应case做完处理后,假设没有遇到break就会接着默认运行以下的case内容(不再去case,由于仅仅有刚进入switch才会去匹配case,已经进入后,case匹配忽略)。直到遇到带break后为止跳出case,否则一直运行完。

    由于仅仅在第一次才做switch推断跳到相应的内容去运行。

    所以,好的程序基本是须要break的。可是有些情况(多个情况相应处理的内容要一样,即前面的几个类型能够不做处理,不须要break。直到最后一个做处理,实现多个类型运行同样的功能,但不添加代码量,更直接)。

    总之,仅仅有在第一次才做推断与选择。进入以后就是安装顺序运行,不break会一直运行到switch结束

    12 C语言中的感叹号。逻辑取反。不同于~的按位取反

    =:表示不等于。。(1)表示为0,!

    (0)表示为1,有取反之意,但仅仅能用在0和1上面。不等于0的会变为0,等于0的变为1



    13.C语言+和<<遇到的一个BUG问题。
    在这里+的优先级高于<<左右移。所以比方a<<8+b,实际是从右往左赋值,8+b相加后来移动a,所以不实现两个字节合并为一个16位的数据。故要加(a<<8)+b才干实现本来的意图。这个误区须要注意

    14.:#define PINMUX0_31_28 0x00000001u,0x00000001UL
    u表示无符号,UL unsigned long int 32位,unsigned long long 64位

    15数组指针和指针数组的差别
    数组指针。为一个指针,int (*a)[10];指向一个数组,相似于函数指针
    指针数组。为一个数组。int* a[10];相似于指针函数,返回的是一个指针。

    16.window以下绝对路径的文件须要用双斜杠来表示\

    17 printf("c=%#x ",c);什么意思?
    %#表示的输出提示方式,假设是8进制,在前面加0,假设是十进制。不加不论什么字符。假设是十六进制,会自己主动加上0x

    18 静态变量在编译的时候初始化,所以初值必须是常量(能够是常数、定义成常数的宏、C++编译器中用const修饰的常量),静态变量不能用变量赋初始值,但在运行时是能够用变量赋值的。


    19 assert函数,用于推断是否为真,满足就继续运行,不然直接终止程序的运行
     
    20.做到4个字节对齐,使用例如以下方式:
    ((CSL_CacheRegsOvly)CSL_CACHE_REGS)->L1DIWC  = ((byteCnt+3)>>2);
    字节数不为4的倍数时。须要多保留一个字的数量,故加3,1+3,2+3,3+3.4字节对齐的方式。
    获得4字节对齐后的字节数字:
    byte_num = (byte + 3) & 0xfc; 这样字节数必为4的倍数。

    21 for循环中假设break,则i++不再运行。

    22.temp = (temp+1)&7.表示temp从0到7变化,循环。

    相似于temp=8时赋值回0.


    23.unsigned char *p;
    unsigned char a[];
    p=a;这样正确。

    unsigned int p1= a;错误,由于是指针类型赋值给了整形的数据类型,类型不匹配。
    unsigned char * p[10]:申明一个指针数组,10个指针,每一个指针指向char类型的空间。
    unsigned char (*p)[10]申明一个数组指针。指向含有10个char类型的空间。指针维护一个10的空间。偏移1加10个空间。

    24.
    多个if会进行分支处理,分别推断后进行是否运行。
    而if 和多个else if等配合时。一旦出现某个满足条件时,不再运行以下的else if的推断,确保仅仅进入一个分支。


    25. char a[3][4]. char **p =a;出现编译错误,类型不匹配不能赋值
    由于a表示的是一个指向一维数组的指针,即char (*a)[3]这个类型.a+1是会偏移3个单位。
    p是一个指针的指针,称为二级指针。所以两者类型不一样。


    26.数组名取地址
    在《C和指针》p142中说到,在以下两中场合下,数组名并非用指针常量来表示。就是当数组名作为sizeof操作符和单目操作符&的操作数时。

    sizeof返回整个数组的长度,而不是指向数组的指针的长度。 取一个数组名的地址所产生的是一个指向数组的指针,而不是一个指向某个指针常量的指针
    所以&a后返回的指针便是指向数组的指针(相似于(*p)[3]),跟a(一个指向a[0]元素的指针)在指针的类型上是有差别的。&a+1是偏移一个数组sizeof大小的尺寸,由于&a是指向数组指针的地址,是一个数值指针。

    可是作为形參时。一级数组名就转为了一个普通的一级指针而已。

    27. 二维数组名不能简单的理解为2级指针,而是要从数组的系统结构上去了解。
    个人觉得二维数组名事实上就是一个指针,可是他指向的数据类型是一维数组的这么个数据类型。即数值指针。事实上能够理解为功能和二维数组名相似。至于数据訪问,全然是编译器来自己主动完毕栈区的訪问。


    28.数值名不能改动,是由于在栈区域内已经定好了ebp,基地址。

    訪 问数组都是基于这个ebp来进行的。所以。给数组名赋值变得没有意义,肯定不同意改动ebp的。

    所以在编译阶段就报错。


    29.
    fseek和发tell配合来完毕确定文件大小的过程。
    fseek(fPtr,0,SEEK_END);
    file_size = ftell(fPtr);
    fseek(fPtr,0,SEEK_SET)。位置指针复位进行读写操作


    30.两数交换不使用第三个缓冲区。三条代码的方法:主要通过运算符来实现。

    A = A^B;
    B = A^B;
    A = B^A;

    A = A+B;
    B = A-B;
    A = A-B;






  • 相关阅读:
    Linix的mysql操作
    Linix安装Mongo
    什么是GitHub
    PHP date, strtotime, mktime处理
    正则表达式及使用
    JavaScript的算法和流程控制总结
    JavaScript的DOM编程总结
    Yii中使用的简单方法
    Mongo数据库的导入导出及使用
    linux-0.11内核 任务的堆栈切换
  • 原文地址:https://www.cnblogs.com/mqxnongmin/p/10812520.html
Copyright © 2011-2022 走看看