精华内容
下载资源
问答
  • c语言深度解析

    2013-10-17 15:16:04
    c语言深度解析
  • C语言深度解析

    2017-12-26 18:15:47
    C语言深度解析,更加深入的理解C语言,更加熟练的掌握c语言
  • 面试c语言深度解析

    2017-06-13 20:49:50
    面试c语言深度解析
  • C语言深度解析笔记

    2019-10-08 11:42:16
    读《C语言深度解析》笔记 2011-10-12 1.C语言标准定义的32个关键字 auto //声明自动变量,缺省时编译器一般默认为autoint //声明整型变量 double //声明双精度变量long //声明长整型变量 char ...

    读《C语言深度解析》笔记   

    2011-10-12

    ContractedBlock.gifExpandedBlockStart.gif1.C语言标准定义的32个关键字
    auto                  //声明自动变量,缺省时编译器一般默认为auto
    int //声明整型变量
    double //声明双精度变量
    long //声明长整型变量
    char //声明字符变量
    float //声明浮点型变量
    short //声明短整型变量
    signed //声明有符号类型变量
    unsigned //声明无符号类型变量
    struct //声明结构体变量
    union //声明联合类型数据
    enum //声明枚举类型
    static //声明静态变量
    switch //用于开关语句
    case //开关语句分支
    default //开关语句中的其他分支
    break //跳出当前循环
    register //声明寄存器变量
    const //声明只读变量
    volatile //说明变量在程序执行中可被隐含地改变
    typedef //用以给数据类型取别名
    extern //声明变量是在其他文件正声明(也可以看做是引用变量)
    return //子程序返回语句(可以带参数,也可不带参数)
    void //声明函数无返回值或无参数,声明空类型指针
    continue //结束当前循环,开始下一轮循环
    do //循环语句的循环体
    while //循环语句的循环条件
    if //条件语句
    else //条件语句否定分支(与if连用)
    for //一种循环语句
    goto //无条件跳转语句
    sizeof //计算对象所占内存空间大小

    ContractedBlock.gifExpandedBlockStart.gif2.定义与声明的区别?
    定义创建了对象并为这个对象分配了内存
    声明没有分配内存

    ContractedBlock.gifExpandedBlockStart.gif3.关键字(register)
    register:这个关键字请求编译器尽可能的将变量存在CPU内部寄存器中而不是通过内存寻址访问以提高效率。

    数据从内存里拿出来先放到寄存器,然后CPU再从寄存器里读取数据处理,处理完后同样把数据通过寄存器存放到内存里,CPU不直接和内存打交道。

    register变量必须是能被CPU寄存器所接受的类型。即register变量必须是一个单个的值,并且其长度应小于或等于整型的长度。而且register变量可能不存放在内存中,所以不能用取址运算符"&"来获取register变量的地址。

    ContractedBlock.gifExpandedBlockStart.gif4.关键字(static)
    //此关键字在C语言中有两个作用,C++对它进行了扩展

    1.修饰变量
    //变量又分为局部和全局变量,但它们都存在于内存的静态区。
    //静态全局变量,作用域仅限于变量被定义的文件中,其他文件即使用extern声明也没法使用。
    准确地说作用域是从定义之处开始,到文件结尾处结束,在定义之处前面的代码行也不可以使用。
    //静态局部变量,在函数体里面定义的,就只能在这个函数里用,同一个文档中的其他函数也用不了。
    由于被static修饰的变量松狮存在内存的静态区,所以即使这个函数运行结束,
    这个静态变量的值还是不会被销毁,函数下次使用时仍然能用。

    2.修饰函数
    //函数前加static使得函数成为静态函数。
    但此处static的含义不是指存储方式,而使指对函数的作用域仅局限于本文件(所以又称内部函数)。
    使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其他文件的函数同名。

    //在C中引入关键字static是为了表示退出一个块后仍然存在的局部变量。
    //随后,static在C中有了第二种含义:用来表示不能被其他文件访问的全局变量和函数。
    为了避免引入新的关键字,所以仍然使用static关键字来表示这第二种含义。

    ContractedBlock.gifExpandedBlockStart.gif5.关键字(sizeof)
    //sizeof是关键字不是函数
    sizeof在计算变量所占空间大小时,括号可以省略,而计算类型大小时不能省略。
    定义int i=0;则:
    sizeof(int)//=4
    sizeof(i)//=4
    sizeof int//错误语句
    sizeof i//=4

    //sizeof (int)*p,表示sizeof((int)*p)

    32位系统下,定义:
    int *p=NULL;
    int a[100];
    那么:
    sizeof(p)//=4
    sizeof(*p)//=4
    sizeof(a)//=400
    sizeof(a[100])//=4
    sizeof(&a)//=4
    sizeof(&a[0])//=4

    void fun(int a[100])
    {
    sizeof(a)//=4
    }


    2011-10-13

    ContractedBlock.gifExpandedBlockStart.gif6.基本数据类型(short.int.long.char.float.double)
    //C数据类型

    {
    //基本数据类型
    {
    //数值类型
    {
    //整型
    {
    短整型short
    整型int
    长整型long
    }

    //浮点型
    {
    单精度型float
    双精度型double
    }
    }

    字符类型char
    }

    //构造类型
    {
    数组
    结构体struct
    共用体union
    枚举类型enum
    }

    指针类型

    空类型void
    }

    ContractedBlock.gifExpandedBlockStart.gif7.关键字(signed、unsigned)
    //32位的signed int类型整数其值表示范围为:-2^31~2^31-1
    //8位的signed char类型其值表示范围为:-2^7~2^7-1
    //32位的unsigned int类型整数其值表示范围为:0~2^32-1
    //8位的unsigned char类型其值表示范围为:0~2^8-1

    思考下面的strlen(a)?
    int main()
    {
    char a[1000];
    int i;
    for(i=0;i<1000;i++)
    {
    a[i]=-1-i;
    }
    printf("%d",strlen(a));
    return 0;
    }
    //for循环内,当i=0时,a[0]=-1。问题的关键在于-1在内存里如何存储。
    在计算机系统中,数值一律用补码表示(存储)。
    主要原因是使用补码,可以将符号位和其它位统一处理;
    同时,减法也可以按加法来处理;
    另外,两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃。
    ////整数的补码与其原码一致
    ////负数的补码:符号位为1,其余为该数绝对值的原码按位取反,然后整个数加1。

    ContractedBlock.gifExpandedBlockStart.gif8.if、else组合
    //与“零值”比较
    bool bTestFlag=FALSE;
    if(bTestFlag) or if(!bTestFlag);

    int *p=NULL;
    if(NULL==p) or if(NULL!=p)

    //if语句注意事项
    先处理正常情况,再处理异常情况

    ContractedBlock.gifExpandedBlockStart.gif9.switch、case组合
    //if、else一般表示两个分支或是嵌套表示少量的分支,但如果分支很多,则使用switch、case组合更合适

    //使用switch、case规则
    1.每个case语句结尾加break,否则多个分支会重叠
    2.最后必须使用default分支

    //case关键字后面的值有什么要求
    case后面只能是整型或字符型的常量或常量表达式

    //case语句的排列顺序
    1.按字母或数字顺序排列各条case语句
    2.把正常情况放在前面,而把异常情况放在后面
    3.按执行频率排列case语句

    //使用case语句其他事项
    1.简化每种情况对应的操作
    2.不要为了使用case语句而可以制造一个变量
    3.把default子句只用于检查真正的默认情况

    ContractedBlock.gifExpandedBlockStart.gif10.do、while、for关键字
    //C语言的三种循环语句:while、do-while、for
    while:先判断while后面括号里的值,如果为真则执行其后面的代码;否则不执行
    do-while:先执行do后面的代码,然后再判断while后面括号里的值,如果为真,循环开始;否则,循环不开始。用法和while没有区别,但相对较少用。
    for:可以很容易的控制循环次数,多用于事先知道循环次数的情况。

    //循环语句的注意点
    1.在多重循环中,尽量将最长的循环放在最内层,最短的循环放在最外层,以减少CPU跨切循环层的次数
    2.for语句的循环控制变量的取值采用"半开半闭区间"写法
    //半开半闭区间:for(n=0;n<10;n++)
    //闭区间:for(n=0;n<=9;n++)
    3.不能在for循环体内修改循环变量,防止循环失控
    4.循环要尽可能的短,使代码清晰
    5.循环嵌套控制在3层内

    //break与continue的区别
    break表示终止本层循环
    continue表示终止本次循环

    ContractedBlock.gifExpandedBlockStart.gif11.关键字(void)
    void作用:
    1.对函数返回的限定
    2.对函数参数的限定

    //void修饰函数返回值和参数
    1.如果函数没有返回值,那么应声明为void类型。在C语言中,凡不加返回值类型限定的函数,就会被编译器作为返回整型值处理。
    2.如果函数无参数,那么应声明其参数为void

    //void指针
    1.谨慎使用void指针类型。ANSI规定,不能对void指针进行算法操作。进行算法操作的指针必须是确定知道其指向数据类型大小的。也就是说必须知道内存目的地址的确切值。
    2.如果函数的参数可以是任意类型指针,那么应该声明其参数为void *
    //void *memcpy(void *dest, const void *src, size_t len);
    //void *memset(void *buffer, int c, size_t num);

    //void不能代表一个真实的变量
    void的出现只是一种抽象的需要,如果正确地理解了面向对象中“抽象基类”的概念,也容易理解void数据类型。正如不能给抽象基类定义一个实例,我们也不能定义一个void变量。

    ContractedBlock.gifExpandedBlockStart.gif12.关键字(return)
    //return用来终止一个函数并返回其后面跟着的值
    return (value); //此括号可以省略。但一般不省略,尤其在返回一个表达式的值时。

    return可以返回什么?例子
    char *Func(void)
    {
    char str[30];
    ...
    return str;
    }
    str属于局部变量,位于栈内存中,在Func结束的时候被释放,所以返回str将导致错误。
    //return语句不可返回指向栈内存的指针,因为该内存在函数体结束时被自动销毁。

    ContractedBlock.gifExpandedBlockStart.gif13.关键字(const)
    //关键字const也许该被替换为readonly
    const修饰的是只读的变量,其值在编译时不能被使用,因为编译器在编译时不知道其存储的内容。
    const推出的初始目的,正是为了取代预编译指令,消除它的缺点,同时继承它的优点。

    //cosnt与define宏的区别
    1.const修饰的只读变量,并且在定义的同时进行初始化
    2.const可以节省空间,避免不必要的内存分配,同时提高效率
    //编译器通常不为普通const只读变量分配存储空间,而使将它们保存在符号表中,
    //这使得它成为一个编译器件的值,没有了存储与读内存的操作,使得它的效率也很高。
    //例如:
    // #define M 3 //宏常量
    // const int N=5; //此时并未将N放入内存中
    // int i=N; //此时为N分配内存,以后不再分配
    // int I=M; //预编译期间进行宏替换,分配内存
    // int j=N; //没有内存分配
    // int J=M; //再次宏替换,又一次分配内存
    const定义的只读变量从汇编的角度看,只是给出了对应的内存地址,而不是像define一样给出的立即数,
    所以,const定义的只读变量在程序运行过程中只有一份拷贝(因为它是全局的只读变量,存放在静态区),
    而define定义的宏常量在内存中有若干个拷贝。
    define宏是在预编译阶段进行替换,而const修饰的只读变量是在编译的时候确定其值。
    define宏没有类型,而const修饰的只读变量具有特定的类型。
    3.修饰一般变量,一般变量是指简单类型的只读变量。
    //这种制度变量在定义时,修饰符const可以用在类型说明符前,也可以用在类型说明符后。如:int const i=2 或 const int i=2;
    4.修饰数组。如int const a[5]={1,2,3,4,5} 或 const int a[5]={1,2,3,4,5};
    5.修饰指针
    //const int *p; //p可变,p指向的对象不可变
    //int const *p; //p可变,p指向的对象不可变
    //int *const p; //p不可变,p指向的对象可变
    //const int *const p; //指针p和p指向的对象都不可变
    6.修饰函数的参数,当不希望这个参数值被函数体内意外改变时使用。
    如:void Fun(const int i);告诉编译器i在函数体中不能改变,从而防止了使用者的一些误操作。
    7.修饰函数的返回值,表示返回值不可被改变。
    如:const int Fun(void);
    8.在另一连接文件中引用const只读变量:
    extern const int i; //正确的声明
    extern const int j=10; //错误,只读变量的值不能改变,注意声明和定义的区别。

    ContractedBlock.gifExpandedBlockStart.gif14.关键字(volatile)
    volatile修饰的变量可以被某些编译器未知的因素更改,比如操作系统,硬件或者其他线程等。
    遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
    例如:
    int i=10;
    int j=i;
    int k=i;
    这时候编译器对代码进行优化,因为在后两条语句中,i没有被用作左值。
    这时候编译器认为i的值没有发生改变,所以从内存中取出i赋给j之后,这个值并没有被丢掉,而是继续用这个值给k赋值。
    编译器不会生成处汇编代码重新从内存里取i值,这样提高了效率。但是要注意在多次赋值中间i没有被用作左值。

    例子:
    volatile int i=10;
    int j=i;
    int k=i;
    volatile告诉编译器i是随时可能发生变化的,每次使用它的时候必须从内存中取出i的值,因而编译器生成的汇编代码会重新从i的地址处读取数据放在k中。

    so。如果i是一个寄存器变量或者表示一个端口数据或者是多个线程的共享数据,就容易出错,所以说volatile可以保证对特殊地址的稳定访问。

    ContractedBlock.gifExpandedBlockStart.gif15.关键字(extern)
    extern可以修饰变量或者函数,以表示变量或者函数的定义在别的文件中。
    从而提示编译器遇到此变量和函数时在其他模块中寻找其定义。

    ContractedBlock.gifExpandedBlockStart.gif16.关键字(struct)
    struct将一些相关联的数据打包成一个整体,方便使用。
    //空结构体有多大?
    结构体所占的内存大小是其成员所占内存之和。如:
    sturct student
    {

    }stu;
    sizeof(stu)=1,为什么?
    假设结构体内只有一个char型的数据成员,那其大小为1byte。
    也就是说非空结构体类型数据最少需要占一个字节的空间,而空结构体类型数据总不能比最小的非空结构体数据所占的空间小,
    所以编译器为每个结构体类型数据至少预留1个byte的空间,则空结构体的大小就定位1个byte。

    //柔性数组
    C99中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员,但结构中的柔性数组成员前面必须至少一个其他成员。
    柔性数组允许结构中包含一个大小可变的数组。sizeof返回的这种结构大小不包括柔性数组的内存。
    包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。

    typedef struct st_type
    {
    int i;
    int a[];
    }type_a;
    这样就定义一个可变长的结构体,用sizeof(type_a)得到的只有4,就是sizeof(i)=sizeof(int)。
    那个0个元素的数组没有占有空间,而后可以进行变长操作。通过下面表达式给结构体分配内存:
    type_a *p=(type_a*)malloc(sizeof(type_a)+100*sizeof(int));
    这样为结构体指针p分配了一块内存。用p->item[n]就能简单地访问可变长元素。
    但是这个时候再用sizeof(*p)测试结构体大小,发现仍然为4.
    因为在定义结构体的时候,以及确定不包含柔性数组的内存大小。所以柔性数组其实与结构体没有关系,算不得结构体的正式成员。

    //struct和class的区别
    在C++里struct关键字与class关键字一般可以通用,只有一个小区别。
    struct的成员默认情况下属性是public,而class是private

    ContractedBlock.gifExpandedBlockStart.gif17.关键字(union)
    //union与struct用法类似
    union维护足够的空间来置放多个数据成员中的“一种”,而不是为每一个数据成员配置空间,在union中所有的数据成员共用一个空间,同一时间只能储存其中一个数据成员,所有的数据成员具有相同的其实地址。
    union StateMachine
    {
    char character;
    int number;
    char *str;
    double exp;
    };
    一个union只配置一个足够大的空间来容纳最大长度的数据成员,以上例而言,最大长度是double,所以StateMachine的空间大小就是double数据类型大小。

    在C++里,union的成员默认属性也是public。
    union主要用来压缩空间。如果一些数据不可能在同一时间同时被用到,则可以使用union。

    //大小端模式对union类型数据的影响
    union
    {
    int i;
    char a[2];
    }*p,u;
    p=&u;
    p->a[0]=0x39;
    p->a[1]=0x38;
    那么p.i=?
    这里需要考虑存储模式:大端模式和小端模式
    大端模式(Big_endian):字数据的高字节存储在低地址中,而字数据的低字节存放在高地址中。
    小端模式(Little_endian):子数据的低字节存储在低地址中,而子数据的高字节存放在高地址中。
    union型数据所占的空间等于其最大的成员所占的空间。对union型的成员的存取都是相对于该联合体基地址的偏移量为0处开始,也就是联合体的访问不论对那个变量的存取都是从union的首地址位置开始。



    转载于:https://www.cnblogs.com/gala/archive/2011/10/12/2208982.html

    展开全文
  • C语言深度解析,解析各种C语言的常见问题和难以理解的问题。
  • 第1章:c编译、链接的过程 第2章:c预编译 第3章:存储类、生命周期、作用域、链接域 第4章:指针与函数 第5章:制作c库、c标准库 第6章:数组、字符串 第7章:结构体、联合体、枚举 第8章:杂项—可变参函数、断言...
  • C语言深度解析 C专家编程 代码大全 C++primer及答案 很好的书
  • 谦虚使人进步,仔细阅读这篇文档,不管是新手、老手还是高手一定会有所收获的。
  • 按照这个作者的说法,C语言没有表面的上的那么简单,他并不是只有简单的数组,指针,函数这些东西,他还有很多我们需要注意的东西 关键字 C语言一共有32个关键字,其中最容易搞错的就是sizeof这个关键字,本人在未读...

    前言

    按照这个作者的说法,C语言没有表面的上的那么简单,他并不是只有简单的数组,指针,函数这些东西,他还有很多我们需要注意的东西

    关键字

    C语言一共有32个关键字,其中最容易搞错的就是sizeof这个关键字,本人在未读这本书的时候,曾经也在man手册中man了sizeof,没有查询到,当时还比较困惑,但是没有多想。
    表(1.1)C 语言标准定义的 32 个关键字
    关键字 意 义
    auto 声明自动变量,缺省时编译器一般默认为 auto
    int 声明整型变量
    double 声明双精度变量
    long 声明长整型变量
    char 声明字符型变量
    float 声明浮点型变量
    short 声明短整型变量
    signed 声明有符号类型变量
    unsigned 声明无符号类型变量
    struct 声明结构体变量
    union 声明联合数据类型
    enum 声明枚举类型
    static 声明静态变量
    switch 用于开关语句
    case 开关语句分支
    default 开关语句中的“其他”分支
    break 跳出当前循环
    register 声明寄存器变量
    const 声明只读变量
    volatile 说明变量在程序执行中可被隐含地改变
    typedef 用以给数据类型取别名(当然还有其他作用)
    extern 声明变量是在其他文件正声明(也可以看做是引用变量)
    return 子程序返回语句(可以带参数,也可不带参数)
    void 声明函数无返回值或无参数,声明空类型指针
    continue 结束当前循环,开始下一轮循环
    do 循环语句的循环体
    while 循环语句的循环条件
    if 条件语句
    else 条件语句否定分支(与 if 连用)
    for 一种循环语句(可意会不可言传)
    goto 无条件跳转语句
    sizeof 计算对象所占内存空间大小

    定义和声明的区别

    定义分配了内存,而声明没有分配内存

    最快的储存类型register

    register:这个关键字要求将变量尽可能放入寄存器中,这样可以提高他的访问速度,但是要是你定义了很多,可能就轮不上你了。他只是尽可能
    寄存器:就是一个个小的储存空间,他离cpu很近,他的存取速度很快,当然他的价格是很贵的,不可能都把存储换成寄存器的
    虽然寄存器的速度很快,但是他只能储存单个数字,而且要小于一个整型,同时他的存储不在内存中,不能使用&来获得他的内存

    static

    是指将一个数值存入一块静态内存中,函数结束这个变量也不会被销毁
    第二个作用用来修饰函数的时候,表示函数只能在自己的文件中调用,同样不用担心自己的文件会和别人重名

    switch ,case组合

    这里要说的主要就是case后面只能跟整形,字符串常量,常量表达式

    同样的case语句在情况比较多的时候,应该有一定的排序,有如下的规则

    1. 按字母或数字顺序排列各条 case 语句。
    2. 把正常情况放在前面,而把异常情况放在后面。
    3. 按执行频率排列 case 语句
    4. 简化每种情况对应的操作。
    5. 不要为了使用 case 语句而刻意制造一个变量。
    6. 把 default 子句只用于检查真正的默认情况。

    void类型

    viod其实没有什么,就是表示空,他要说用处的话就是用在函数的返回值上,它可以定义一个void * 指针,它可以赋值给任何指针,非常方便,就比如我们常用的malloc函数
    void不能代表一个真实的变量,他只是一个抽象的变量,像 void a就是不合法,所以的数据都应该有属性的

    const类型

    const 类型修饰的变量为只读变量,编译器通常不为普通 const 只读变量分配存储空间,而是将它们保存在符号表中,这使 得它成为一个编译期间的值,没有了存储与读内存的操作,使得它的效率也很高。 const从汇编的角度来看,只是给出了地址,而没有给出立即数

    const修饰指针

    constint *p; // p 可变,p 指向的对象不可变
    int const p; // p 可变,p 指向的对象不可变
    int * const p; // p不可变, p 指向的对象可变
    const int
    const p; //指针 p 和 p 指向的对象都不可变
    一般修饰指针的时候记住一个原则就好了,就是const离哪个近,哪个就是不能改变的

    最易变的关键字----volatile

    它可以提供对特殊地址的稳定访问,因为在他的修饰下,编译器每次都要从内存中去取值,而不是在平常的情况下,只有他不为左值就不会从内存中取值,如果 这个变量是一个寄存器变量或者表示一个端口数据或者是多个线程的共享数据,就容易出错,所以说 volatile 可以保证对特殊地址的稳定访问。

    展开全文
  • Linux内核C语言深度解析

    千次阅读 2019-06-24 19:01:08
    R C 称为传统C语言,在C语言标准统一前,这个是最权威。 ANSI C:是ANSI(美国国家标准协会), 再K&R C基础上,统一了各大编译器厂商的不同标准,并做了一些扩展,也称作 C89/C90, 至此C标准统一起来。 C99: A...

    本文来源于GitChat体验课

    第01课: C标准发展

    C标准的四个阶段:

    K&R C

    ANSI C

    C99

    C11

    K&R C 称为传统C语言,在C语言标准统一前,这个是最权威。

    ANSI C:是ANSI(美国国家标准协会), 再K&R C基础上,统一了各大编译器厂商的不同标准,并做了一些扩展,也称作 C89/C90, 至此C标准统一起来。

    C99: ANSI 1999年在ANSI C上做了扩展

    C11, 2011年发布的最新的标准。

    不同的编译器在支持C标准的同时,也做了一些其他的扩展。

    比如51单片机上, Keil for C51上支持一些关键字,如data,code,bit等

    GCC编译器,扩展支持零长度数组,语句表达式等。

    个人观点,如果要开发跨平台的C语言程序,尽量使用C标准内的语法,而不要使用不常见的扩展语法。

    第02课: 内核驱动中的指定初始化

    指定初始化数组:

    标准C中常见的初始化方法:

    int a[10] ={1,2,3,4}; 按照顺序初始化,未覆盖到的元素都扩展赋值为0

     

    GNU C支持C99标准。(GNU&GCC, GCC全称是 GNU C Compiler)

    C99标准,支持指定初始化,比如100个数组b[100],只初始化b[10] 和b[30]

    int b[100] = { [10] = 1, [30] = 2 };

     

    数组范围初始化,如[10] 到 [30] 赋值为1, [50]到[60]赋值为2

    int b[100] = { [10 ... 30] = 1, [50 ... 60] = 2 }; ... 前后必须由空格

    这种范围... 在sitch-case 语句中也可以用

    switch(i)
    {
        case 1:
            printf("1\n");
            break;
        case 2 ... 8:
            printf("%d\n",i)
            break;
        defalut:
            break;
    }

     

    指定初始化结构体:

    struct student{
        char name[20];
        int age;
    };
    struct student stu1 = {"Ben", 18};
    struct student stu2 = // 指定初始化
    {
        .name = "will",
        .age = 28 // 后面没有逗号
    };

    指定初始化的好处,当结构体成员顺序发生变动,如

    那么第一种stu1 初始化地方就得改, 而第二种方法完全不用改.

    linux内核驱动中注册,经常遇到这种用法。

    struct student{
        int age;
        char name[20];
        char number[20];
    };

    第03课:语句表达式 -- 构造宏定义的好帮手

    语句表达式:

    GNU C对C标准进行了扩展,允许一个表达式里内嵌语句,允许表达式内部使用局部变量、for循环和goto跳转语句。这样的表达式,我们称之为语句表达式。

    语句表达式最外面用小括号()括起来,里面用一对大括号{}包起来的是代码块,代码块里允许内嵌各种语句。

    语句表达式内使用for循环:

    int main()
    {
        int sum = 0;
        sum =
        ({
            int s = 0;
            for( int i = 0; i < 10; i++ )
            {
                s = s + i;
            }
            s;
        });
        printf("sum = %d\n",sum);
        return 0;
    }

    编译方法:gcc -o test test.c -std=gnu99 -Wall

    如果不加-std=gnu99 则会报错。(参考;https://blog.csdn.net/u012075739/article/details/26516007/

    语句表达式的值邓玉最后一个表达式的值,所以再for循环的后面我们要加一个 s; 如果不加这一句则sum=0。 或者你将这一行改成100; sum的值就是100,这是因为语句表达式的值总邓玉最后一个表达式的值。

    语句表达式内使用goto语句:

    int main()
    {
        int sum = 0;
        sum =
        ({
            int s = 0;
            for( int i = 0; i < 10; i++ )
            {
                s = s + i;
            }
            goto here;
            s;
        });
        printf("sum = %d\n",sum);
    here:
        printf("here\n");
        printf("sum = %d\n",sum);
        return 0;
    }

    此时,sum=0

    写宏定义,求两个数的最大值:MAX(a,b)

    一般写法:

    #define MAX(a,b) ((a)>(b)?(a):(b))

    如果对于自加运算和自减运算就会有问题。

    比如 MAX(a++, b++)

    进阶写法1:

    #define MAX(a,b) ({ \
        int _x = a;     \
        int _y = b;     \
        _x > _y ? _x : _y; \
    })

    但是该方法仅能用于int类型,对于其他类型的比较又要重新写这个宏定义。

    进阶写法2:

    #define MAX(type,a,b) ({ \
        type _x = a;         \
        type _y = b;         \
        _x > _y ? _x : _y;  \
    })

    将数据类型作为一个参数传进来。

     

    展开全文
  • C语言深度解析,解开程序员面试笔试的秘密。以含金量勇敢挑战国内外同类书籍。资料来源于网络,请下载此资源时感谢共享资源给我们的网友和作者。
  • C语言深度解析,属于《嵌入式工程师-系列课程》之一。 《嵌入式工程师-系列课程》课程分为两部分 第一部分:《计算机体系结构》 分为4篇,硬件篇、软件篇、网络篇、IT行业篇 第二部分:具体的嵌入式技术课程 内容...
    不可错过的《C语言深度解析》—1147人已学习 
    课程介绍    
    201708271011132725.jpg
        C语言深度解析,属于《嵌入式工程师-系列课程》之一。 《嵌入式工程师-系列课程》课程分为两部分 第一部分:《计算机体系结构》 分为4篇,硬件篇、软件篇、网络篇、IT行业篇 第二部分:具体的嵌入式技术课程 内容包括,c基础、c、Linux基础/、Linux系统编程和网络编程、8051单片、STM32单片、Arm裸机、uboot/系统移植、Linux驱动
    课程收益
        希望各位同学通过《c语言深度解析》课程的学习,能够深度掌握C语言工程应用的高级知识,学完、学好这门课后,可以毫不犹豫说自己已经买入C语言高手行列,掌握了这门课所要的C知识和技术后,应该说可以基本胜任目前上市场上大多数C相关的开发工作。
    讲师介绍
        张先凤更多讲师课程
        2008年毕业于沈阳航空航天大学电子信息专业,长期从事嵌入式 、互联网、物联网项目研发和教学,精通c/c++/java等语言,精于单片机、嵌入式(linux)安卓开发和教学,4年实际产品开发经验和4年嵌入式安卓教学经验。
    课程大纲
        1.课程知识点大纲  30:32
        2.VMware和Ubuntu的介绍和安装1  19:59
        3.VMware和ubuntu下载和安装2  32:58
        4.Ubuntu 和windows的操作界面对比 1  26:13
        5.ubuntu和windows的家目录和主目录  29:54
        6.ubuntu和windows图形操作界面对比 2  27:33
        7.ubuntu和windows的命令行对比  34:03
        8.windows内置命令和外置命令1  31:40
        9.Windows常见内置命令和外置命令  31:04
        10.Linux操作命令1  28:48
        11.Linux操作命令 2  26:52
        12.ubuntu和windows的文本编辑  40:26
        13.windows下的c程序开发  29:03
        14.Windows下的c程序开发  11:20
        15.Ubuntu下的C程序开发  13:17
        16.高级语言与低级语言的区分界限  17:25
        17.1951年~今,高级语言的发展历史  35:57
        18.为什么这么多高级语言,什么是编程范式  25:29
        19.语言排行榜  35:14
        20.1969~1972:c语言诞生期  22:23
        21.1972~1976:c语言幼年时期  16:58
        22.1976~1983:C语言标准时期  34:46
        23.编译器对c标准的支持情况  9:23
        24.GCC编译器介绍 1  29:34
        25.GCC编译器介绍 2  19:46
    大家可以点击【查看详情】查看我的课程
    展开全文
  • 这本C语言教程出自资深C语言应用专家,根据多年应用经验,深刻揭示C语言应用的深度内涵。
  • 讲解C语言的一些注意点,值得一看。文档时pdf格式的啊。
  • c语言深度解析》第5、6章 制作c库与c标准库、数组与字符串 2008年毕...

空空如也

空空如也

1 2 3 4 5 ... 19
收藏数 372
精华内容 148
关键字:

c语言深度解析

c语言 订阅