C语言理解——static、extern等

目 录

  • 1、static 修饰 局部变量
  • 2、static 修饰 全局变量
  • 3、static 修饰 函数
  • 4、extern 修饰 变量或函数
  • 5、register 修饰 变量
  • 6、const 修饰 变量
  • 7、typedef 起别名
  • 8、#define 文本替换


1、static 修饰 局部变量

普通的局部变量创建后是放在栈区中,这种局部变量进入作用域时创建,出了作用域就销毁;

static修饰后的局部变量则放在静态区中,它改变了局部变量的存储位置,从而使得变量的生命周期延长,延长至程序结束才销毁。

static修饰局部变量只改变生命周期,不改变作用域。

2、static 修饰 全局变量

全局变量的作用域十分的广,只要在一个源文件中定义后,这个程序中的所有源文件、对象以及函数都可以调用,生命周期更是贯穿整个程序。文件中的全局变量想要被另一个文件使用时就需要进行外部声明(用extern关键字进行声明)。

全局变量本身是具有外部链接属性的,在A文件中定义的全局变量,在B文件中可以通过【链接】来使用;

如果全局变量被static修饰,那这个外部链接属性就会被修改成内部链接属性,此时这个全局变量就只能在自己的源文件中使用;

3、static 修饰 函数

static修饰函数时会改变函数的链接属性,从而使得函数的作用域变小。
函数本身也是有外部链接属性的;
被static修饰后,函数的外部链接属性被修改成内部链接属性,使得这个函数只能在自己的源文件内被使用,因此函数的作用域就变小了。

4、extern 修饰 变量或函数

extern一般用在变量名前或函数名前,用来说明 “ 此变量/函数在别的源文件中定义了,要在此处声明进行引用 ”。

文件 A.c
int a = 0; //定义并初始化变量

文件 B.c
extern int a; //声明进行引用,不要出现在头文件中

声明操作是没有分配内存的,只有定义才分配内存。声明可以多次,定义只能一次。最好不要在头文件中定义变量,在头文件中只声明,不定义。尽量不要在头文件中出现 “ extern int value ” 这类声明。

在头文件中使用条件编译 #ifndef 防止出现重复引入同一个头文件,导致提示 “ 变量被多次定义 ”的错误。确保头文件中的内容只被编译一次。编译器只在第一次处理这个头文件时会执行头文件内容。

#ifndef HEADER_FILE_NAME_H
#define HEADER_FILE_NAME_H
//头文件内容
#endif

在头文件开头加上 #pragma once 也可以防止同一个头文件被包含多次,但它不支持跨平台。

5、register 修饰 变量

register修饰的变量可能是放到寄存器中,这样可以提高CPU对该变量的访问速度,这类变量通常是需要频繁调用的。register不能修饰局部静态变量。register是很少用的。

6、const 修饰 变量

const修饰的变量表示不能再改变变量的值,再次赋值也不行,定义的时候就把值确定了,该变量是只读的。

7、typedef 起别名

给现有的数据类型起新的名称。

#include
typedef int INT32;
typedef unsigned char BYTE;

typedef struct _demo
{
	short s;
	BYTE b1;
	BYTE b2;
	INT32 i;
} DEMO;

int main()
{
	INT32 i32;
	BYTE byte;
	DEMO d;
	printf("%d , %d\r\n",sizeof(INT32),sizeof(i32));
	printf("%d , %d\r\n",sizeof(BYTE),sizeof(byte));
	printf("%d , %d\r\n",sizeof(DEMO),sizeof(d));
	return 0;
}

运行结果:
4 , 4
1 , 1
8 , 8

新名称具有文件作用域,从它被定义的地方开始到文件结尾都有效。
由编译器在编译时处理的,所以具有类型检查的功能,类型安全性高。
在同一作用域内,不同类型不能起相同的别名。

与指针结合时,能保证类型的一致性。

typedef int* INT_PTR;

INT_PTR p1, p2;  // 两个都是 int 型指针

总结:更适合用于定义新的数据类型

适用情况: 为复杂的数据类型创建新的名称,易读易懂,从名称体现出描述性、特定属性和用途。

8、#define 文本替换

给常量做简单的文本替换。

作用域从其定义点开始,直到被取消定义或遇到编译单元的结束,相对较广。
在预编译阶段就进行简单的文本替换,所以没有类型检查,可能会导致一些意外的错误,类型安全性较差。
定义的宏可以在同一作用域内多次重新定义,但通常不建议这样做。

与指针结合时,可能会产生意外的结果。

#define PTR_INT int*

PTR_INT p3, p4;  // 只有 p3 是 int 型指针,p4 是 int 型

总结:更适合用于定义常量和简单的文本替换。

应用情况:被多处使用的常量或配置参数,简短的代码片段,决定是否包含或屏蔽部分代码片段。

C语言理解——结构体struct

你可能感兴趣的:(c语言,开发语言)