C深剖关键字(1)

简介: 目录一:auto 1.1 局部变量与全局变量 1.2 auto相关二:register三: static 四:sizeof

一:auto

      1.1 局部变量与全局变量

局部变量与全局变量定义:


局部变量:包含在代码块中的变量叫做局部变量。局部变量具有临时性。进入代码块,自动形成局部变量,退出代码块自动 释放。[网上很多说函数中的变量是局部变量,不能说错,但说法是不准确的]


全局变量:在所有函数外定义的变量,叫做全局变量。全局变量具有全局性。


代码块:用{}括起来的区域,就叫做代码块


变量的作用域 - 补充内容:


作用域概念:指的是该变量的可以被正常访问的代码区域


局部变量:只在本代码块内有效


全局变量:整个程序运行期间,都有效


变量的生命周期 - 补充内容:


生命周期概念:指的是该变量从定义到被释放的时间范围,所谓的释放,指的是曾经开辟的空间”被释放“


局部变量: 进入代码块,形成局部变量[开辟空间],退出代码块,"释放"局部变量


全局变量: 定义完成之后,程序运行的整个生命周期内,该变量一直都有效


特殊情况:局部与全局同名优先局部

#include <stdio.h>
int g_x = 100; //全局变量
int main()
{
  int g_x = 10; //局部变量,与全局同名
  printf("g_x:%d\n", g_x); //输出的是局部,也就是局部和全局同名的时候,优先局部。所以,强烈不建议这样干。
  return 0;
}

   1.2 auto相关

如何使用:


一般在代码块中定义的变量,即局部变量,默认都是auto修饰的,不过一般省略auto


默认的所有变量都是auto吗?


不是,一般用来修饰局部变量


中断一下:后面我们所到的,局部变量,自动变量,临时变量,都是一回事。我们统称局部变量


例如:

#include<stdio.h>
int main()
{
  for (int i = 0; i < 5; i++)
  {
    printf("%d\n", i);
    if (1)
    {
      auto int j = 1;
      printf("before=%d\n", j);
      j++;
      printf("after1=%d\n", j);
    }
  }
  return 0;
}

image.png总结:


//只能用来修饰局部变量,不能用来修饰全局变量。


//此关键字有点老,不用也问题不大


二:register(最快的关键字)

其实,CPU主要是负责进行计算的硬件单元,但是为了方便运算,一般第一步需要先把数据从内存读取到CPU内,那 么也就需要CPU具有一定的数据临时存储能力。


注意:CPU并不是当前要计算了,才把特定数据读到CPU里面,那样太慢了。


所以现代CPU内,都集成了一组叫做寄存器的硬件,用来做临时数据的保存。


存储金字塔:

image.png

寄存器的认识:


当前,各位童鞋可以不关系硬件细节,只要知道CPU内集成了一组存储硬件即可,这组硬件叫做寄存器。


寄存器存在的本质:


在硬件层面上,提高计算机的运算效率。因为不需要从内存里读取数据啦。


register 修饰变量:


尽量将所修饰变量,放入CPU寄存区中,从而达到提高效率的目的


那么什么样的变量,可以采用register呢?


1. 局部的(全局会导致CPU寄存器被长时间占用)


2. 不会被写入的(写入就需要写回内存,后续还要读取检测的话,register的意义在哪呢?)


3. 高频被读取的(提高效率所在)


4. 如果要使用,请不要大量使用,因为寄存器数量有限


这里除了上面的,再有一点,就是register修饰的变量,不能取地址(因为已经放在寄存区中了嘛,地址是内存相关的概念)

#include<stdio.h>
int main()
{
  register int pass = 100;
  printf("%d\n", pass);
  //printf("%d\n", &pass);   // err
  //一旦使用register寄存器,可以正常访问,但不能使用&
  return 0;
}

我的意见:该关键字,不用管,因为现在的编译器,已经很智能了,能够进行比人更好的代码优化。 早期编译器需要人为指定register,来进行手动优化,现在不需要了。


三: static

引言:先讲解下在某文件下访问其它文件内容(全局变量或函数)的情况


我们都清楚快文件访问时要先声明,再访问才能避免编译器出现报错。


例如:


当我们在test.c文件中定义以下变量


image.png


此时需要在main.c文件中进行访问,则需要在访问前进行声明,否则编译器出错!


image.png


只要是声明,最好都带上extern


//变量声明必须带上extern     //函数声明建议带上extern


//声明和定义尽量保持一致


由此可见:


1.全局变量可以跨文件访问吗?   可以!


2.函数可以跨文件访问吗?   可以!


有没有可能,我们不想让全局变量或者函数跨文件访问,只想在本文件内部访问?


此时引出重要关键字 static:


image.png


当我们在test.c文件中对g_val变量进行static修饰时,在main.c文件中访问报错,但在test.c内部访问g_val却是可以的


image.png


结论一:static修饰全局变量,该变量只在本文件内被访问,不能被外部文件直接访问,但可以通过函数间接访问


image.png


此时运行是没有问题的,但此时我们对函数进行static修饰时,编译器同样出错了


image.png


结论二:static修饰函数,该函数只能在本文件内部被访问,不能在外部其他文件直接访问


但是有这么一种情况,在test.c文件中再定义一个函数,将show函数嵌套在内,如:


image.png


此时再main.c文件进行如下操作并运行发现没有问题。

image.png


通过上述简单例子的操作,我们且可以得到以下结论:static项目维护,提供安全保证


static修饰全局变量和函数,限制的是作用域


static修饰局部变量:


先看代码:

#include<stdio.h>
static void fun()
{
    int i = 0;
  i++;
  printf("%d ", i);
}
int main()
{
  int i = 0;
  for (i = 0; i < 10; i++)
  {
    fun();
  }
}

image.png i局部变量,局部临时性,函数调用的时候开辟空间并初始化,函数结束释放空间


当我们采用static int i = 0;时,结果就是我们想看到的从1-10


static int i = 0;

此时我们不难发现加上static后,i在fun运行的过程中,并没有被释放!!!

image.png

加以例子证明:!!!

image.png

结论三: static修饰局部变量,更改局部变量的生命周期,就是将临时变量转换为全局变量,但作用域不变,只是生命周期变了


将上述static结论汇总:


结论一:static修饰全局变量,该变量只在本文件内被访问,不能被外部文件直接访问,但可以通过函数间接访问


结论二:static修饰函数,该函数只能在本文件内部被访问,不能在外部其他文件直接访问


结论三: static修饰局部变量,更改局部变量的生命周期,就是将临时变量转换为全局变量,但作用域不变,只是生命周期变了


四:sizeof

sizeof作用:确定一种类型对应在开辟空间的时候的大小


#include<stdio.h>
int main()
{
  printf("%d\n", sizeof(char)); //1
  printf("%d\n", sizeof(short)); //2
  printf("%d\n", sizeof(int)); //4
  printf("%d\n", sizeof(long)); //4
  printf("%d\n", sizeof(long long)); //8
  printf("%d\n", sizeof(float)); //4
  printf("%d\n", sizeof(double)); //8
  return 0;
}

下面有一些特殊情况:

  int a = 10;
  printf("%d\n", sizeof(a));    // 1     4
  printf("%d\n", sizeof(int));  // 2     4
  printf("%d\n", sizeof a);     // 3     4
  //printf("%d\n", sizeof int); // 4     err

在这四个标号中,第四个是错的,别的运行结果都为4

由第三个标号我们可以得出一个基本事实,sizeof不是函数,它是关键字或操作符

sizeof可以求自定义类型大小:

#include<stdio.h>
int main()
{
  int* p = NULL;
  int arr[10];
  int* test[3];
  printf("%d\n", sizeof(p));     // 4
  printf("%d\n", sizeof(arr));   // 40
  printf("%d\n", sizeof(test));  // 12
  return 0;
}
相关文章
|
3月前
|
Java 程序员 开发者
深入解读:synchronized关键字背后的“黑科技”!
深入解读:synchronized关键字背后的“黑科技”!
29 4
|
6月前
|
Java 编译器
Java编程语言中,关键字和标识符
Java编程语言中,关键字和标识符
48 1
|
Java
关于关键字volatile的一二
关于关键字volatile的一二
73 0
|
JavaScript 前端开发
|
JavaScript 前端开发
|
JavaScript 前端开发
|
存储 算法 编译器
深剖关键字(跑路人笔记2)
深剖关键字(跑路人笔记)
深剖关键字(跑路人笔记2)
|
存储 编译器 Linux
C深剖关键字(4)
目录 一:volatile关键字 二:extern关键字 三:struct关键字
C深剖关键字(4)
|
编译器 程序员 Linux
C深剖关键字(3)
目录 一:void关键字 二:return关键字 三:const关键字
C深剖关键字(3)
|
存储 编译器
C深剖关键字(5)
目录 一:union关键字 二:enum关键字 三:typedef关键字
C深剖关键字(5)