C语言基础知识点解析(extern,static,typedef,const)

yizhihongxing

关于C语言基础知识点解析的完整攻略,我将分为四个部分来详细讲解extern、static、typedef、const的定义、用法和示例。

1. extern详解

extern是外部变量或函数的声明关键字。若在一个文件中定义了一个全局变量或函数,而在另一个文件中需要使用该变量或函数,则必须在使用之前用extern进行声明,表示该变量或函数是外部可见的。

extern声明全局变量:

/* file1.c */
int num = 10;

/* file2.c */
extern int num;
int add(int a) {
  return a + num;
}

/* main.c */
#include <stdio.h>
extern int num;
int add(int);
int main() {
  printf(“Add: %d”, add(5)); // should print 15
  return 0;
}

在上面的代码中,file1.c中定义了num,file2.c中通过extern int num声明了num,确保现在可以在file2.c中使用num。最后,main.c通过包含file2.h头文件并链接外部编译单元,可以正确地链接num。

extern声明函数:

/* file1.c */
int num = 5;

/* file2.c */
extern int num;
void hello() {
  printf("Hello, The Number is %d\n", num);
  return 0;
}

/* main.c */
#include <stdio.h>
void hello();
int main() {
  hello();
  return 0;
}

在上面的代码中,file1.c中还是定义了num,在file2.c的函数中使用了num,最后main.c中通过包含file2.h头文件并链接外部编译单元,可以正确地调用hello()。

2. static详解

static关键字在C语言中可以用于不同的场景,以表示不同的含义。在全局变量、局部变量、函数声明、函数定义、结构体中,static都有不同的含义。

static声明全局变量:

/* file1.c */
static int num = 5;

/* file2.c */
extern int num;
void hello() {
  printf("Hello, The Number is %d\n", num);
}

/* main.c */
#include <stdio.h>
void hello();
int main() {
  hello();
  num++;
  hello(); // should print The Number is 5 and 6
  return 0;
}

在上面的代码中,static在全局变量中表示该变量只能在当前编译单元内使用,即该变量的生命周期只存在于当前文件中。在file1.c中定义了一个全局的静态变量num,file2.c中可以通过extern引入num。main.c中调用了hello()两次,分别输出5和6的值,因为static变量num的生命周期只存在于当前文件中,所以累加之后输出的结果不会有变化。

static声明局部变量:

/* file1.c */
#include <stdio.h>
void foo() {
  int test = 5;
  static int static_test = 5; 
  test++;
  static_test++;
  printf(“test: %d, static_test: %d\n”, test, static_test);
}

/* file2.c */
#include <stdio.h>
void foo();

int main() {
  foo();
  foo();
  foo();
  return 0;
}

在上面的代码中,在函数内部使用static声明的变量只具有一次初始化,然后一直存在于函数的生命周期中,不会因为函数执行完毕而被销毁。上述代码中,test每次调用foo函数都会重置为5,而static_test每次调用foo函数都会累加,一直存在于函数的生命周期中,因此输出结果为“test: 6, static_test: 6”、“test: 6, static_test: 7”、“test: 6, static_test: 8”。

static声明函数:

/* file1.c */
static void foo() {
  printf("Hello World\n");
}

/* file2.c */
#include <stdio.h>
static void foo() {
  printf("Hello Everyone\n");
}

int main() {
  foo();
  return 0;
}

在函数声明和函数定义中使用static关键字,表示该函数只能在当前编译单元内部使用,其他文件无法引用该函数。上述代码中,file1.c中定义了一个静态函数foo,file2.c同样定义了一个静态函数foo,但是在main函数中只会输出“Hello World”,因为静态函数foo只能在file1.c中被访问。

3. typedef详解

在C语言中,typedef允许我们创建新的数据类型别名。通过typedef关键字,可以对已经存在的数据类型进行取别名操作。

typedef int new_int;

上述代码的意思是将int类型重新取别名为new_int。在代码中,我们可以定义变量或参数时使用这个别名来代替int类型。

new_int num = 10; 

在这种情况下,num的数据类型就是新定义的new_int。

typedef与结构体:

不仅如此,typedef与结构体配合使用还可以定义新的数据类型。

typedef struct {
  int x;
  int y;
} Point;

上述代码将一个结构体定义为名为Point的新数据类型。以后可以使用Point类型来定义结构体类型的变量:

Point p1 = {1, 2};
p1.x = 5;

typedef与指针:

typedef也可与指针类型一起使用。指针的定义从char,int等等改为了自定义的别名,如CharPtr、IntPtr等。

typedef char* CharPtr;
typedef int* IntPtr;

CharPtr str = "hello";
IntPtr num = 5;

typedef与函数:

typedef也可以用于函数指针。

typedef int (*FuncPtr)(int);

int add(int a) {
  return a + 1;
}

int minus(int a) {
  return a - 1;
}

int main() {
  FuncPtr func = add;
  printf("%d\n", func(5)); // should print 6

  func = minus;
  printf("%d\n", func(5)); // should print 4
  return 0;
}

上述代码定义了一个FuncPtr类型的函数指针,该指针指向一个int(int)函数。

4. const详解

const是一个关键字,表示定义的变量是只读的,在程序运行的过程中不能修改。

const定义常量:

const int num = 7;

上述代码中,将整数7定义为只读变量num。在程序运行过程中,不能对该变量进行修改。

指针和const:

在指针前加const会使指针所指向的变量成为只读的。

int a = 5;
const int* b = &a;

*b = 6; // ERROR

上述代码中,const int前加了*,因此其表示的是一个指向常量的指针。在程序运行过程中,不能修改指针b所指向的变量a。

const和函数:

在函数定义中,const可以表示该参数是只读的。

void print(const char* str) {
  printf("%s", str);
}

上述代码表示参数str是只读的,在函数内部不能对该参数修改。

注意事项:

需要注意的是,在C语言中const并不是对变量的值进行限制,而仅仅是对第一次定义时所赋的值进行限制,之后对该变量的操作不被限制。

const int num = 10;
int* ptr = (int*)&num;
*ptr = 11;
printf("num = %d\n", num); // should print 10 instead of 11

上述代码中,虽然num通过const定义成为只读变量,但是我们可以通过指针的类型强转与指针操作,来对其进行修改。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言基础知识点解析(extern,static,typedef,const) - Python技术站

(0)
上一篇 2023年6月26日
下一篇 2023年6月26日

相关文章

  • vue如何通过某个字段获取详细信息

    获取某个字段的详细信息,实际上是一个“筛选出符合条件的对象”的问题,因此实现这个功能需要涉及到数组的筛选和对象属性的访问。 下面是一个具体的实现步骤: 通过filter()方法筛选数组中符合条件的对象 在Vue中,可以使用filter()方法对数组进行筛选。该方法的参数是一个函数,用于对数组中的每个元素进行判断,如果返回true,则当前元素会被保留在新数组中…

    other 2023年6月25日
    00
  • 使用压缩的方式将Windows下的zip压缩包上传到Linux系统的方法解析

    使用压缩的方式将Windows下的zip压缩包上传到Linux系统的方法解析 在将Windows下的zip压缩包上传到Linux系统之前,我们需要确保已经安装了适当的工具和软件。以下是一个详细的攻略,包含了两个示例说明。 步骤一:安装必要的软件 在Linux系统上,我们需要安装unzip工具来解压缩zip文件。使用以下命令来安装unzip: sudo apt…

    other 2023年8月6日
    00
  • JVM的类加载过程详细说明

    关于JVM的类加载过程,可以分为以下3个阶段:加载、连接和初始化。下面分别介绍: 加载 类加载的过程就是将类的.class文件中的二进制码读入到内存中,将其放在方法区(JDK 1.8之前称为永久代,JDK 1.8之后将永久代移除,改为元空间)内,然后在堆区构造一个java.lang.Class对象,用来封装类在方法区内的数据结构。 类的加载阶段由类加载器完成…

    other 2023年6月25日
    00
  • 智能硬件设计中如何选什么音频接口i2s、pdm、tdm?

    智能硬件设计中如何选择音频接口? 在智能硬件设计中,选择合适的音频接口非常重要。常见的音频接口有I2S、PDM和TDM。下面是一些选择音频接口的考虑因素: 1. 数据传输速度 I2S和TDM都是串行音频接口,可以提供高速数据传输。I2S可以提供高达24位的数据传输,而TDM可以提供更高的数据传输速度。PDM是并行音频接口,传输速度相对较慢。 2. 系统复杂度…

    other 2023年5月8日
    00
  • Android实现可滑动的自定义日历控件

    Android实现可滑动的自定义日历控件攻略 1. 概述 在Android中实现可滑动的自定义日历控件可以提供用户友好的日历浏览体验。本攻略将介绍一种实现方法,使用RecyclerView和自定义Adapter来展示日历,并通过手势监听实现滑动功能。 2. 步骤 2.1 创建项目和布局文件 首先,创建一个新的Android项目,并在布局文件中添加一个Recy…

    other 2023年9月6日
    00
  • 如何查找应用软件连接域名真实IP修改Hosts

    如何查找应用软件连接域名真实IP修改Hosts攻略 1. 确定应用软件连接的域名 首先,我们需要确定应用软件连接的域名。这可以通过以下几种方式来实现: 网络抓包工具:使用网络抓包工具(如Wireshark、Fiddler等)来监视应用软件的网络流量。通过分析抓包数据,我们可以找到应用软件连接的域名。 应用软件配置文件:有些应用软件会将其连接的域名写入配置文件…

    other 2023年7月31日
    00
  • 使用latex插入数学公式(二)

    使用LaTeX插入数学公式(二) 在上一篇文章中,我们介绍了如何使用LaTeX插入数学公式,包括行内公式和行间公式的使用方法。然而,有一些特殊的数学公式需要我们掌握一些额外的知识才能够正确地插入。本文将进一步介绍如何在LaTeX中插入分数、根号、希腊字母等特殊符号,以及如何对多行公式进行对齐。 插入分数 插入分数可以使用\frac{分子}{分母}的命令,其中…

    其他 2023年3月29日
    00
  • 学会批处理

    学会批处理的完整攻略 批处理是Windows操作系统下的一种命令行脚本语言,可以通过一系列的命令实现自动化操作、批量操作等。学会批处理可以有效提升工作效率和操作便利性。下面将分为以下四个部分详细讲解如何学会批处理。 1.入门学习 学习基本命令:批处理中常用的命令有echo、set、if、for、goto等。需要学会掌握这些基本命令的使用方法和语法。 熟悉批处…

    other 2023年6月26日
    00
合作推广
合作推广
分享本页
返回顶部