精华内容
下载资源
问答
  • 外部关键字概念
    千次阅读
    2021-05-22 11:28:16

    C语言关键字解析

    C语言关键字有32个,如表1所示。虽然简单,但还是让一些初学者犯错,譬如sizeof,好多初学者都认为是函数,其中包括我的一些同学,他们学过有好多年了,如此看来,有时我们追求高深的内容,往往会忽略基础的简单的内容!

    表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计算对象所占内存空间大小

    在这里我们也不一一讲解每个关键字,只是讲讲比较容易被人忽略的或者易出错的关键字说明一下。

    在讲之前,先说明一下,定义和声明的区别:

    定义:编译器在创建一个对象时,为该对象申请开辟的内存空间,这个空间的的名字就是变量名或者对象名。同一个变量名在摸个区域内只能定义一次,重复定义会出现错误的。

    声明:有两种作用,

    1.告诉编译器,这个变量或者函数,我已经定义了(开辟空间了),但是在别的地方,我先说明一下,免得编译器报错。当然,声明可以多次出现。

    2.告诉编译器,这个变量名或者对象名,我先预定了,其他地方不可以用了。和在饭馆吃饭(人多)要提前预约一样的道理。

    定义和声明最本质的区别在于,声明没开辟空间,而定义则创建对象(变量)并开辟了空间。这是最重要的一点。

    一. auto,register,extern,static,四种关键字

    C语言说明变量的时,同时给出了两个方面的信息:数据类型和存储类。C语言中提供了存储说明符auto,register,extern,static说明的四种存储类别。

    1.auto是变量是C语言最常用的。编译器在默认的缺省情况下,所有变量都是auto的。对于函数的形参,也是auto型的。

    2.extern, 语言中存在这样的一种变量,在一个函数中合法出现的同时,又可以在其他的函数中合法出现,这就是外部变量。它的生命周期是整个程序的执行周期。

    3.register,寄存器变量,其值存放在寄存器中,访问速度快。有最快的关键字的称呼。虽然寄存器的速度非常快,但是使用register修饰符也有些限制的:register变量必须是能被CPU寄存器所接受的类型。意味着register变量必须是一个单个的值,并且其长度应小于或等于整型的长度。而且register变量可能不存放在内存中, 所以不能用取址运算符 “&”来获取register变量的地址。

    4.static静态变量,两个作用。第一个作用:修饰变量,都存在内存的静态区。

    静态局部变量:出现在函数体内,生命周期是整个程序的执行过程,由于被static修饰的变量总是存在内存的静态区,即使该函数生命结束,其值不会被销毁,同样要修改该变量,就要到函数内部完成,所以用起来比较安全,起到信息屏蔽的作用。

    静态全局变量:出现在函数体外,作用域仅限于变量被定义的文件中,其他文件即使用extern声明也没法使用他。

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

    二.基本数据类型----short、int、long、char、float、double这些关键字都是基本的数据类型,每种类型占据的内存空间不一样,其实每种类型相当于一个模型,再通俗点就是一个模子。具体占多少个字节,可以用关键字sizeof去测一下。另外就就是存储问题。不论是float还是double在存储方式上都遵从IEEE的规范,float遵从的是IEEE R32.24 ,而double遵从的是R64.53。#include int main(){float a=999.999;float b=0.005;printf("%lf/n",a+b-1000.004);return 0;}看看得到的结果并不是0,按数学计算本来应该是0,但由于浮点数的存储有微小的误差从而导致计算结果不是0double m=3.3;cout<

    部分内容参考了陈正冲 《C语言深度解剖》。

    还有这个网站上关于字节对齐写得不错,可以看看!

    更多相关内容
  • java关键字概念

    2022-04-23 09:25:13
    在类的外部或者对于子类而言,它们是不可见的。 所有类成员的默认访问范围都是 package 访问,也就是说,除非存在特定的访问控制修饰符,否则,可以从同一个包中的任何类访问类成员。 2) protected 受保护的 ...

    watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAeG1oLXN4aC0xMzE0,size_9,color_FFFFFF,t_70,g_se,x_161. 访问控制

     

    1) private 私有的

    private 关键字是访问控制修饰符,可以应用于类、方法或字段(在类中声明的变量)。 只能在声明 private(内部)类、方法或字段的类中引用这些类、方法或字段。在类的外部或者对于子类而言,它们是不可见的。 所有类成员的默认访问范围都是 package 访问,也就是说,除非存在特定的访问控制修饰符,否则,可以从同一个包中的任何类访问类成员。

     

     

     

    2) protected 受保护的

    protected 关键字是可以应用于类、方法或字段(在类中声明的变量)的访问控制修饰符。可以在声明 protected 类、方法或字段的类、同一个包中的其他任何类以及任何子类(无论子类是在哪个包中声明的)中引用这些类、方法或字段。所有类成员的默认访问范围都是 package 访问,也就是说,除非存在特定的访问控制修饰符,否则,可以从同一个包中的任何类访问类成员。

     

     

     

    3) public 公共的

    public 关键字是可以应用于类、方法或字段(在类中声明的变量)的访问控制修饰符。 可能只会在其他任何类或包中引用 public 类、方法或字段。所有类成员的默认访问范围都是 package 访问,也就是说,除非存在特定的访问控制修饰符,否则,可以从同一个包中的任何类访问类成员。

     

     

     

     

     

     

     

    2. 类、方法和变量修饰符

    1) abstract 声明抽象

    abstract关键字可以修改类或方法。abstract类可以扩展(增加子类),但不能直接实例化。abstract方法不在声明它的类中实现,但必须在某个子类中重写。采用 abstract方法的类本来就是抽象类,并且必须声明为abstract。

     

     

     

    2) class类

    class 关键字用来声明新的 Java 类,该类是相关变量和/或方法的集合。类是面向对象的程序设计方法的基本构造单位。类通常代表某种实际实体,如几何形状或人。类是对象的模板。每个对象都是类的一个实例。要使用类,通常使用 new 操作符将类的对象实例化,然后调用类的方法来访问类的功能。

     

     

     

    3) extends 继承、扩展

    extends 关键字用在 class 或 interface 声明中,用于指示所声明的类或接口是其名称后跟有 extends 关键字的类或接口的子类。子类继承父类的所有 public 和 protected 变量和方法。 子类可以重写父类的任何非 final 方法。一个类只能扩展一个其他类。

     

     

     

    4) final 最终、不可改变

    final 关键字可以应用于类,以指示不能扩展该类(不能有子类)。final 关键字可以应用于方法,以指示在子类中不能重写此方法。一个类不能同时是 abstract 又是 final。abstract 意味着必须扩展类,final 意味着不能扩展类。一个方法不能同时是 abstract 又是 final。abstract 意味着必须重写方法,final 意味着不能重写方法。

     

     

     

    5) implements实现

    implements 关键字在 class 声明中使用,以指示所声明的类提供了在 implements 关键字后面的名称所指定的接口中所声明的所有方法的实现。类必须提供在接口中所声明的所有方法的实现。一个类可以实现多个接口。

     

     

     

    6) interface 接口

    interface 关键字用来声明新的 Java 接口,接口是方法的集合。

     

    接口是 Java 语言的一项强大功能。任何类都可声明它实现一个或多个接口,这意味着它实现了在这些接口中所定义的所有方法。 

     

    实现了接口的任何类都必须提供在该接口中的所有方法的实现。一个类可以实现多个接口。

     

     

     

    7) native 本地

    native 关键字可以应用于方法,以指示该方法是用 Java 以外的语言实现的。

     

     

     

    8) new 新,创建

    new 关键字用于创建类的新实例。 

     

    new 关键字后面的参数必须是类名,并且类名的后面必须是一组构造方法参数(必须带括号)。 

     

    参数集合必须与类的构造方法的签名匹配。 

     

    = 左侧的变量的类型必须与要实例化的类或接口具有赋值兼容关系。

     

     

     

    9) static 静态

    static 关键字可以应用于内部类(在另一个类中定义的类)、方法或字段(类的成员变量)。 

     

    通常,static 关键字意味着应用它的实体在声明该实体的类的任何特定实例外部可用。

     

    static(内部)类可以被其他类实例化和引用(即使它是顶级类)。在上面的示例中,另一个类中的代码可以实例化 MyStaticClass 类,方法是用包含它的类名来限定其名称,如 MyClass.MyStaticClass。 

     

    static 字段(类的成员变量)在类的所有实例中只存在一次。 

     

    可以从类的外部调用 static 方法,而不用首先实例化该类。这样的引用始终包括类名作为方法调用的限定符。

     

    模式:public final static <type> varName = <value>; 通常用于声明可以在类的外部使用的类常量。在引用这样的类常量时需要用类名加以限定。在上面的示例中,另一个类可以用 MyClass.MAX_OBJECTS 形式来引用 MAX_OBJECTS 常量。

     

     

     

    10) strictfp 严格,精准

    strictfp的意思是FP-strict,也就是说精确浮点的意思。在Java虚拟机进行浮点运算时,如果没有指定strictfp关键字时,Java的编译器以及运行环境在对浮点运算的表达式是采取一种近似于我行我素的行为来完成这些操作,以致于得到的结果往往无法令人满意。而一旦使用了strictfp来声明一个类、接口或者方法时,那么所声明的范围内Java的编译器以及运行环境会完全依照浮点规范IEEE-754来执行。因此如果想让浮点运算更加精确,而且不会因为不同的硬件平台所执行的结果不一致的话,那就请用关键字strictfp。

     

    可以将一个类、接口以及方法声明为strictfp,但是不允许对接口中的方法以及构造函数声明strictfp关键字

     

     

     

    11) synchronized线程、同步

    synchronized 关键字可以应用于方法或语句块,并为一次只应由一个线程执行的关键代码段提供保护。 

     

    synchronized 关键字可防止代码的关键代码段一次被多个线程执行。 

     

    如果应用于静态方法,那么,当该方法一次由一个线程执行时,整个类将被锁定。 

     

    如果应用于实例方法,那么,当该方法一次由一个线程访问时,该实例将被锁定。 

     

    如果应用于对象或数组,当关联的代码块一次由一个线程执行时,对象或数组将被锁定。

     

     

     

    12) transient 短暂

    transient 关键字可以应用于类的成员变量,以便指出该成员变量不应在包含它的类实例已序列化时被序列化。

     

    当一个对象被串行化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。

     

    Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。

         transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。

     

    13) volatile 易失

    volatile 关键字用于表示可以被多个线程异步修改的成员变量。 

     

    注意:volatile 关键字在许多 Java 虚拟机中都没有实现。 volatile 的目标用途是为了确保所有线程所看到的指定变量的值都是相同的。

     

    Java 语言中的 volatile 变量可以被看作是一种 “程度较轻的 synchronized”;与 synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少,但是它所能实现的功能也仅是 synchronized 的一部分。

     

     

     

     

     

     

     

    3. 程序控制语句

    1) break 跳出,中断

    break 关键字用于提前退出 for、while 或 do 循环,或者在 switch 语句中用来结束 case 块。 

     

    break 总是退出最深层的 while、for、do 或 switch 语句。

     

     

     

    2) continue 继续

    continue 关键字用来跳转到 for、while 或 do 循环的下一个迭代。 

     

    continue 总是跳到最深层 while、for 或 do 语句的下一个迭代。

     

     

     

    3) return 返回

    return 关键字会导致方法返回到调用它的方法,从而传递与返回方法的返回类型匹配的值。 

     

    如果方法具有非 void 的返回类型,return 语句必须具有相同或兼容类型的参数。 

     

    返回值两侧的括号是可选的。

     

     

     

    4) do 运行

    do 关键字用于指定一个在每次迭代结束时检查其条件的循环。 

     

    do 循环体至少执行一次。 

     

    条件表达式后面必须有分号。

     

     

     

    5) while 循环

    while 关键字用于指定一个只要条件为真就会重复的循环。

     

     

     

    6) if 如果

    if 关键字指示有条件地执行代码块。条件的计算结果必须是布尔值。 

     

    if 语句可以有可选的 else 子句,该子句包含条件为 false 时将执行的代码。 

     

    包含 boolean 操作数的表达式只能包含 boolean 操作数。

     

     

     

    7) else 否则

    else 关键字总是在 if-else 语句中与 if 关键字结合使用。else 子句是可选的,如果 if 条件为 false,则执行该子句。

     

     

     

    8) for 循环

    for 关键字用于指定一个在每次迭代结束前检查其条件的循环。 

     

    for 语句的形式为 for(initialize; condition; increment) 

     

    控件流进入 for 语句时,将执行一次 initialize 语句。 

     

    每次执行循环体之前将计算 condition 的结果。如果 condition 为 true,则执行循环体。 

     

    每次执行循环体之后,在计算下一个迭代的 condition 之前,将执行 increment 语句。

     

     

     

    9) instanceof 实例

    instanceof 关键字用来确定对象所属的类。

     

     

     

    10) switch 观察

    switch 语句用于基于某个表达式选择执行多个代码块中的某一个。 

     

    switch 条件的计算结果必须等于 byte、char、short 或 int。 

     

    case 块没有隐式结束点。break 语句通常在每个 case 块末尾使用,用于退出 switch 语句。 

     

    如果没有 break 语句,执行流将进入所有后面的 case 和/或 default 块。

     

     

     

    11) case 返回观察里的结果

    case 用来标记 switch 语句中的每个分支。 

     

    case 块没有隐式结束点。break 语句通常在每个 case 块末尾使用,用于退出 switch 语句。 

     

    如果没有 break 语句,执行流将进入所有后面的 case 和/或 default 块。

     

     

     

    12) default 默认

    default 关键字用来标记 switch 语句中的默认分支。 

     

    default 块没有隐式结束点。break 语句通常在每个 case 或 default 块的末尾使用,以便在完成块时退出 switch 语句。 

     

    如果没有 default 语句,其参数与任何 case 块都不匹配的 switch 语句将不执行任何操作。

     

     

     

     

     

    4. 错误处理

    1)

    展开全文
  • 闭包是一个常见的概念,我们通常可以将其与回调函数配合使用,可以使代码更加简洁易读。这篇文章主要介绍了PHP 闭包获取外部变量和global关键字声明变量的区别,需要的朋友可以参考下
  • 先来说说 static 关键字。本篇只讲静态方法的使用与后期绑定的知识点。 static 什么时候用来修饰方法 static 关键字大家都知道是用来修饰方法与属性的。 那么大家在项目中会在哪些场景下使用它? 我遇到过几个项目...
  • 什么是“关键字”?关键字就是已被C语言本身使用,不能作其它用途使用的字,例如关键字不能用作变量名、函数名等。那“关键字”到底有多关键?简单得说,就是如果不掌握它们的使用方法,程序就不能按照我们的设计产生...
  • 本文详细解读一下volatile关键字如何保证变量在多线程之间的可见性,对Java中volatile关键字实现原理感兴趣的朋友一起通过本文学习吧
  • 主要介绍了Java中static关键字的作用和用法详细介绍,主要讲了静态方法、静态变量、静态类、static和final一块用等内容。需要的朋友可以参考下
  • public class Body {//外部类 public class Heart{//成员内部类 //内部类的方法 public void beat(){ System.out.println("跳动..."); System.out.println("我叫:"+name); } } ...
  • static关键字:static可以用于修饰局部变量以扩展局部变量的生存期。extern关键字:只能用于扩展没有被static关键字修饰的全局变量。
  • 主要给大家介绍了关于kotlin中object关键字的三种使用场景,文中通过示例代码介绍的非常详细,对大家学习或者使用kotlin具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
  • 这这文件里的内容适合Java初学者,这里边包含了final这个关键字该如何定义以及用法、生存周期等知识点。这也是小编在刚开学学习JavaSE时记录的一些笔记,里面的内容非常适合JavaSE入门者学习,都是浅显易懂的话语,...
  • 主要介绍了浅析java 的 static 关键字用法的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
  • 主要介绍了C#中的Internal关键字小结的相关资料,需要的朋友可以参考下
  • C语言关键字

    2015-04-07 18:25:59
    C语言volatile关键字的描述,介绍volatile的使用与注意事项
  • 保留关键字概念

    2017-08-16 10:03:03
    保留关键字(reserved word)指在高级语言中已经定义过的字,使用者不能再将这些字作为变量名或过程名使用...所以我去网上搜了搜保留关键字概念。 C语言保留关键字编辑 C89中(C语言标准)中, 类型说明保留字:int,l
    保留关键字(reserved word)指在高级语言中已经定义过的字,使用者不能再将这些字作为变量名或过程名使用。每种程序设计语言都规定了自己的一套保留关键字。


    在做题时遇到过这样的错误,我把next改为Next就好了,next可能是判题机的一个保留关键字。所以我去网上搜了搜保留关键字的概念。

    C语言保留关键字

    类型说明保留字:int,long,short,float,double,char,unsigned,signed,const,void,volatile,enum,struct,union
    语句定义保留字:if,else,goto,switch,case,do,while,for,continue,break,return,default,typedef
    存储类说明保留字:auto,register,extern,static
    长度运算符保留字:sizeof
    具体含义如下:
    auto           指定变量的存储类型,是默认值
    break         跳出循环或switch语句
    case         定义switch中的case子句
    char         定义字符型变量或指针
    const 定义常量或参数
    continue 在循环语句中,回到循环体的开始处重新执行循环
    default 定义switch中的default子句
    do 定义do-while语句
    double 定义双精度浮点数变量
    else 定义枚举类型
    enum 声明外部变量或函数
    extern 声明外部变量或函数
    float 定义浮点型变量或指针
    for 定义for语句
    goto 定义goto语句
    if 定义if语句或if-else语句
    int 定义整型变量或指针
    long 定义长整型变量或指针
    register 指定变量的存储类型是寄存器变量,Turbo c中用自动变量代替
    return 从函数返回
    short 定义短整型变量或指针
    signed 定义有符号的整型变量或指针
    sizeof 获取某种类型的变量或数据所占内存的大小,是运算符
    static 指定变量的存储类型是静态变量,或指定函数是静态函数
    struct 定义结构体类型
    switch 定义switch语句
    typedef 为数据类型定义别名
    union 定义无符号的整型或字符型变量或指针
    unsigned 定义无符号的整型变量或数据
    void 定义空类型变量或空类型指针,或指定函数没有返回值
    volatile 变量的值可能在程序的外部被改变
    while 定义while或do-while语句

    展开全文
  • C语言常见关键字及使用

    千次阅读 2020-05-31 19:20:11
    修饰函数 extern 函数 在定义函数时如果在函数首部的最左端冠以关键字extern,则表示此函数是外部函数,可供其他文件调用。C语言规定,如果在定义函数时省略extern,则隐含为外部函数。 extern修饰函数声明。从本质...

    static

    static作用有三个:

    1.修饰全局变量

    static 全局变量

    • 当一个进程的全局变量被声明为static之后,它的中文名叫静态全局变量。
    • 静态全局变量和其他的全局变量的存储地点并没有区别,都是在.data段(已初始化)或者.bss段(未初始化)内,但是它只在定义它的源文件内有效,其他源文件无法访问它。

    结果展示如下:
    1.c

    #include <stdio.h>
      static int num = 10;
    

    2.c

    #include <stdio.h>
      extern int num;
      int main(int argc, char *argv[])
      {
         printf ("num:%d\n",num);
         return 0;
       }
    

    在这里插入图片描述
    把static删除,结果如下:
    在这里插入图片描述

    2.修饰局部变量

    static 局部变量

    普通的局部变量在栈空间上分配,这个局部变量所在的函数被多次调用时,每次调用这个局部变量在栈上的位置都不一定相同。

    static局部变量中文名叫静态局部变量。与普通局部变量的区别:
    1)位置:静态局部变量被编译器放在全局存储区.data(注意:不在.bss段内,原因见3)),所以它虽然是局部的,但是在程序的整个生命周期中存在。
    2)访问权限:静态局部变量只能被其作用域内的变量或函数访问。也就是说虽然它会在程序的整个生命周期中存在,由于它是static的,它不能被其他的函数和源文件访问。
    3)值:静态局部变量如果没有被用户初始化,则会被编译器自动赋值为0,以后每次调用静态局部变量的时候都用上次调用后的值。这个比较好理解,每次函数调用静态局部变量的时候都修改它然后离开,下次读的时候从全局存储区读出的静态局部变量就是上次修改后的值。

    这两者的区别在于非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。
    而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效,
    在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。

    #include <stdio.h>
    
    void PrintTest (void);
    
    int main(int argc, char *argv[])
    {
    	int tmp;
       
    	for (tmp = 0; tmp < 5; tmp++) {
    		
    		int tmp1 = 10;
    
    		printf ("\n");
    
        PrintTest();
    	}
      
      printf ("static  num : %d     static num address : %p \n",StaticNum,&StaticNum);
    
    	return 0;
    }
    
    
    void PrintTest (void)
    {
    	static int StaticNum = 0;
    	int Num = 0;
     
    	printf ("static  num : %d     static num address : %p \n",StaticNum,&StaticNum);
      printf ("        num : %d\n",Num);
    
      StaticNum++;
    	Num++;
    }
    

    在这里插入图片描述

    3.修饰函数

    static 函数

    static函数与普通函数作用域不同,仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static修饰的函数),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件.

    相信大家还记得C++面向对象编程中的private函数,私有函数只有该类的成员变量或成员函数可以访问。在C语言中,也有“private函数”,它就是接下来要说的static函数,完成面向对象编程中private函数的功能。

    简单测试一下,在main函数里面调用另一个文件里面用static修饰的函数
    main.c

    #include "test.h"
    
    int main(int argc, char *argv[])
    {
      MyPrint ();
      return 0;
    }
    

    test.h

    #ifndef  TEST_
    #define  TEST_
    
    #include <stdio.h>
    
    static void MyPrint (void);
    
    #endif
    

    function.c

    #include "test.h"
    
    static void MyPrint (void)
    {
      printf ("print from function !\n");
    }
    

    编译就出现了错误,结果如下:
    在这里插入图片描述

    extern

    extern 变量

    1.修饰变量

    只能用于扩展没有被static关键字修饰的全局变量。
    在C语言中,修饰符extern用在变量或者函数的声明前,用来说明“此变量/函数是在别处定义的,要在此处引用”。
    默认情况下全局变量只能在定义它的文件中使用(从定义该全局变量开始到所在文件的文件尾),但如果在另一个文件中将这个变量声明为外部变量,那么这个变量的作用域将被扩展到另外一个文件中。也可以在定义全局变量之前声明该变量,从而在文件中可以在定义该全局变量前使用该全局变量。

    main.c

    #include "func.h"
    int num = 20;
    
    int main (void)
    {
      Func();
      return 0;
    }
    

    func.h

    #ifndef  FUNC_
    #define  FUNC_
    
    #include <stdio.h>
    
    void Func (void);
    
    #endif
    

    func.c

    #include "func.h"
    
    void Func (void)
    {
      extern int num;
      int i;
      printf ("num : %d\n",num);
    }
    

    结果:
    在这里插入图片描述

    2.修饰函数

    extern 函数

    在定义函数时如果在函数首部的最左端冠以关键字extern,则表示此函数是外部函数,可供其他文件调用。C语言规定,如果在定义函数时省略extern,则隐含为外部函数。
    extern修饰函数声明。从本质上来讲,变量和函数没有区别。函数名是指向函数二进制块开头处的指针。使用extern修饰函数,这样做的一个明显的好处是,会加速程序的编译(确切的说是预处理)的过程,节省时间。在大型C程序编译过程中,这种差异是非常明显的。

    3.在c++中使用

    extern修饰符可用于指示C或者C++函数的调用规范。

    比如在C++中调用C库函数,就需要在C++程序中用extern “C”声明要引用的函数。这是给链接器用的,告诉链接器在链接的时候用C函数规范来链接。主要原因是C++和C程序编译完成后在目标代码中命名规则不同。

    const

    const其实就是constant的简写
    修饰变量,限定这个变量为只读,意思是这个变量不能更改

    1.修饰普通变量

    const 普通变量

    #include <stdio.h>
    
    int main (void)
    {
      const int num = 5;
    
      num = 9;
    
      return 0;
    }
    
    zl@zl-VirtualBox:~/workspace/4$ gcc 3.c
    3.c: In function ‘main’:
    3.c:7:3: error: assignment of read-only variable ‘num’
       num = 9; 
       ^
    

    如上,在用const修饰普通变量后,后面再修改这个变量 编译器就会报错

    其实const就是告诉编译器这个变量被const修饰,我们可以看下有无const修饰的汇编代码的差异。发现汇编没有差别,这里就不贴代码了。

    我们可以绕过编译器,用指针去修改这个变量,如下:

    #include <stdio.h>
    
    int main (void)
    {
      const int num = 5;
    
      int *p = &num;
      *p = 9;
    
      printf ("num : %d\n",num);
    
      return 0;
    }
    
    zl@zl-VirtualBox:~/workspace/4$ gcc 3.c 
    3.c: In function ‘main’:
    3.c:7:12: warning: initialization discards ‘const’ qualifier from pointer target type [enabled by default]
       int *p = &num;
                ^
    zl@zl-VirtualBox:~/workspace/4$ ./a.out 
    num : 9
    

    这里使用指针修改,虽然编译器报告了warning,但是我们仍然可以看到被const修饰的num的值已经改变。

    2.修饰数组

    const 数组

    数组元素不允许修改

    const int arry[] = {1,2,3,4,5};
    

    3.修饰指针

    主要有三种情况:

    3.1 常量指针

    const放在 * 左侧位置,叫做 常量指针,表示该指针指向的对象是只读的

    int a = 10;
    int b = 20;
    const int *p = &a;
    p = &b;
    
    int a = 10;
    int b = 20;
    int const *p = &a;
    p = &b;
    

    3.2 指针常量

    const放在*的右侧,叫做 指针常量,限定了指针本身是只读的,即不可变的。

    int a = 10;
    int b = 20;
    int * const p = &a;
    *p = 50;
    p = &b; //编译错误,这个时候指针本身是只读的
    

    3.3常量指针常量

    指针不可变,指针指向的内容也不可变

    int a = 10;
    int b = 20;
    const int * const p = &a;
    *p = 50;  //编译错误
    p = &b;   //编译错误
    

    4. 修饰函数形参

    我们在ubuntu下man strcpy这个函数

    char *strcpy(char *dest, const char *src);
    

    上面用了const,这里的const表示传入的指针变量仅用于访问数据,这里理解为字符串。

    5. 修饰全局变量

    对全局变量增加const修饰,就可以避免全局变量被更改。

    const int num  = 20;
    
    extern const int num;
    

    volatile

    1.编译器优化

    内存访问速度远不及CPU处理速度,为提高机器整体性能。

    1. 硬件方面:入硬件高速缓存Cache,加速对内存的访问。另外在现代CPU中指令的执行并不一定严格按照顺序执行,没有相关性的指令可以乱序执行,以充分利用CPU的指令流水线,提高执行速度。
    2. 软件方面:一种是在编写代码时由程序员优化,另一种是由编译器进行优化。
      编译器优化常用的方法有:
    3. 将内存变量缓存到寄存器。由于访问寄存器要比访问内存单元快的多,编译器在存取变量时,为提高存取速度,编译器优化有时会先把变量读取到一个寄存器中;以后再取变量值时就直接从寄存器中取值。但在很多情况下会读取到脏数据,严重影响程序的运行效果。
    4. 调整指令顺序充分利用CPU指令流水线,常见的是重新排序读写指令。

    2.volatile详解

    volatile字面意思是“易变的”,在C里面,我们可以理解为“直接存取原始内存地址”
    提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,告诉编译器对该变量不做优化,都会直接从变量内存地址中读取数据,从而可以提供对特殊地址的稳定访问。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。(简洁的说就是:volatile关键词影响编译器编译的结果,用volatile声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不要进行编译优化,以免出错)

    2.1用处

    1. 防止编译器优化普通变量
    #include <stdio.h>
    
    int main (void)
    {
      int i;
     // volatile int num;
      int num;
    
      for (i = 0; i < 1000000; i++) {
        num = i;
      }
    
      return 0;
    }
    
    
    zl@zl-VirtualBox:~/workspace/4$ time ./a.out 
    real	0m0.005s
    user	0m0.005s
    sys	0m0.000s
    
    #include <stdio.h>
    
    int main (void)
    {
      int i;
      volatile int num;
      //int num;
    
      for (i = 0; i < 1000000; i++) {
        num = i;
      }
    
      return 0;
    }
    
    
    zl@zl-VirtualBox:~/workspace/4$ time ./a.out 
    real	0m0.007s
    user	0m0.007s
    sys	0m0.000s
    
    
    1. 中断服务程序操作其他程序的变量。
      变量在触发某中断程序中修改,而编译器判断主函数里面没有修改该变量,因此可能只执行一次从内存到某寄存器的读操作,而后每次只会从该寄存器中读取变量副本,使得中断程序的操作被短路。
    2. 多任务环境下各任务间共享的标志。
      在本次线程内, 当读取一个变量时,编译器优化时有时会先把变量读取到一个寄存器中;以后,再取变量值时,就直接从寄存器中取值;当内存变量或寄存器变量在因别的线程等而改变了值,该寄存器的值不会相应改变,从而造成应用程序读取的值和实际的变量值不一致 。
    3. 存储器映射的硬件寄存器
      操作某些特定的寄存器时,可能要对同一个寄存器进行反复操作,如果不用volatile,就有可能存在只有最后一次操作有效,前面几次操作就被忽略。这样就会出现错误,参考访问EC space。

    restrict

    restrict是c99标准引入的,它只可以用于限定和约束指针,并表明指针是访问一个数据对象的唯一且初始的方式.即它告诉编译器,所有修改该指针所指向内存中内容的操作都必须通过该指针来修改,而不能通过其它途径(其它变量或指针)来修改;这样做的好处是,能帮助编译器进行更好的优化代码,生成更有效率的汇编代码.如 int *restrict ptr, ptr 指向的内存单元只能被 ptr问到,任何同样指向这个内存单元的其他指针都是未定义的,直白点就是无效指针。restrict 的出现是因为 C 语言本身固有的缺陷,C 程序员应当主动地规避这个缺陷,而编译器也会很配合地优化你的代码.

    register修饰的变量必须是CPU所能接受的类型,就是该变量必须是单个值且小于等于整型长度(想想汇编就明白了)
    由于该变量不存在内存,所以不能用&取地址

    关键字restrict通过允许编译器优化某几种代码增强了计算支持。它只可用于指针,并表明指针是访问一个数据对象的惟一且初始的方式。为了清楚这样做为何有用,我们需要看一些例子。考虑下面的代码:

    int ar[10];
    int * restrict restar = (int *) malloc(10 * sizeof(int));
    int * par = ar;
    

    这里,指针restar是访问由malloc()分配的内存的惟一且初始的方式。因此,它可以由关键字restrict限定。然而,par指针既不是初始的,也不是访问数组ar中数据的惟一方式,因此不可以把它限定为restrict。
    现在考虑下面这个更复杂的例子,其中n是一个int:

    for(n=0; n < 10; n++)
    {
    par[n] += 5;
    restart[n] += 5;
    ar[n] *= 2;
    par[n] += 3;
    restar[n] += 3;
    }
    

    知道了restar是访问它所指向数据块的惟一初始方式,编译器就可以用具有同样效果的一条语句来代替包含restar的两个语句:

    restar[n] += 8;
    

    然而,将两个包含par的语句精简为一个语句将导致计算错误:

    par[n] += 8;
    

    出现错误结果的原因是循环在par两次访问同一个数据之间,使用ar改变了该数据的值。
    没有关键字restrict,编译器将不得不设想比较糟的那种情形,也就是两次使用指针之间,其他标识符可能改变了数据的值。使用restrict关键字之后,编译器可以放心地寻找计算的捷径。
    可以将关键字restrict作为指针型函数参量的限定词使用。这意味着编译器可以假定在函数体内没有其他标识符修改指针指向的数据,因而可以试着优化代码,反之则不然。例如,C库中有两个函数可以从一个位置把数据复制到另一个位置。在C99标准下,他们的原型如下:

    void * memcpy(void * restrict dst, const void * restrict src, size_t n);
    void * memmove(void * dst, const void * src, size_t n);
    

    两个函数都从位置src把n个字节复制到dst中。函数memcpy()要求两个位置之间不重叠,但memmove()没有这个要求。把dst和src声明为restrict意味着每个指针都是相应数据的惟一访问方式,因此他们不能访问同一数据块。这满足了不能有重叠的要求。函数memmove()允许重叠,它不得不在复制数据时更加小心,以防在使用数据前就覆盖了数据。
    关键字restrict有两个读者。一个是编译器,它告诉编译器可以自由地做一些有关优化的假定。另一个读者是用户,它告诉用户仅使用满足restrict要求的参数。一般,编译器无法检查您是否遵循了这一限制,如果您蔑视它也就是在让自己冒险。

    以上参考《C Primer Plus》

    展开全文
  • 主要介绍了IOS 关键字const 、static、extern详解的相关资料,这里对关键字如何使用,及在IOS开发中的意义做了详解,需要的朋友可以参考下
  • C语言关键字分类整理

    2021-05-23 00:39:50
    C语言总览:强类型,面向过程简洁、灵活:32个关键字(C99标准新增5个,C11新增7个),9种控制语句,34种运算符数据类型丰富,运算符丰富结构化(控制语句)、模块化(函数)灵魂、特色:指针高级语言中的低级语言:直接...
  • 详解C中volatile关键字

    2014-07-25 09:39:40
    一个生动的例子,详解了Volatile关键字对变量的声明在不同编译环境下可能造成不同的结果
  • 首先,描述了static关键字去修饰java类、方法、变量、代码块...1、static关键字基本概念 我们可以一句话来概括:方便在没有创建对象的情况下来进行调用。 也就是说:被static关键字修饰的不需要创建对象去调用,直接根
  • 关键字驱动
  • 接下来我们就看一下几个常用关键字的用法,包括const,cregister,far,__interrupt等。
  • 常见关键字 14 常见关键字 14.1 常用关键字 Python里的关键字可通过内置的函数查看。见如下命令: >>>import keyword >>>keyword.kwlist ['False', 'None','True', 'and', 'as', 'assert', 'break', 'class', '...
  • 常见关键字

    2022-04-18 20:55:07
    常见关键字 C语言提供了丰富的关键字,这些关键字都是语言本身预先设定好的,用户自己是不能创造关键字的。 auto break case char const continue default do double else enum extern float for goto if int ...
  • Java中 this关键字详解

    2020-10-18 00:48:54
    this关键字是Java中常用的关键字,可以用于任何实例方法内指向当前对象,也可以指向对其调用当前方法的对象,或者在需要当前类型对象引用时使用。 在Java中,当一个对象创建后,Java虚拟机(JVM)就会给这个对象分配...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 139,955
精华内容 55,982
关键字:

外部关键字概念