一、static关键字
1、修饰局部变量–静态局部变量
特点:
1.1、static修饰局部变量,会影响局部变量的生命周期,本质改变了局部变量的储存位置,生命周期变长,为整个周期,其作用域还是局部,静态局部变量存储于进程中的全局数据区。
1.2、静态局部变量(c)是在编译时赋初值的,即只赋初值一次,在程序运行时它已有初值。以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时的值。
1.3、如果在定义局部变量时不给它赋初值,那么对静态局部变量来说,编译时自动赋初值0(对数值型变量),或者空字符’\0’(对字符变量)。而对自动变量来说,其值是个不确定的值。
2、修饰全局变量–静态全局变量
特点:
全局变量本身具有外部链接属性,即全局变量的作用域是整个工程,但是如果用 static 修饰全局变量,就会使得全局变量失去外部链接属性,变成内部链接属性,即只能在自己的文件中使用,所以 static 修饰的全局变量时,只能在自己的 .c 文件中使用。
3、修饰函数
特点:
函数默认是有外部链接属性的,但是被 static 修饰后,会使得函数失去外部链接属性,变成内部链接属性。所以 static 修饰的函数只能在自己所在的 .c 文件内部使用,不能在其他文件中使用。和 static 修饰全局变量 很像。
总结
1、static修饰变量
a. 修饰函数中局部变量:
声明周期延长:该变量不随函数结束而结束初始化:只在第一次调用该函数时进行初始化记忆性:后序调用时,该变量使用前一次函数调用完成之后保存的值存储位置:不会存储在栈上,放在数据段
b. 修饰全局变量
改变该变量的链接属性,让该变量具有文件作用域,即只能在当前文件中使用
c. 修饰变量时,没有被初始化时会被自动初始化为0
2、static修饰函数
改变该函数的链接属性,让该函数具有文件作用域,即只能在当前文件中使用
二、const关键字
a、修饰局部变量
const int n=5;
int const n=5;
作用:修饰变量使得变量n的值不能被改变
这两种写法是一样的,都是表示变量n的值不能被改变了,需要注意的是,用const修饰变量时,一定要给变量初始化,否则之后就不能再进行赋值了。
b、修饰常量静态字符串
eg:const char* str="fdsafdsa";
如果没有const的修饰,我们可能会在后面有意无意的写str[4]=’x’这样的语句,这样会导致对只读内存区域的赋值,然后程序会立刻异常终止。有了const,这个错误就能在程序被编译的时候就立即检查出来,这就是const的好处。让逻辑错误在编译期被发现。
c、常量指针与指针常量
常量指针是指针指向的内容是常量,可以有一下两种定义方式
const int * n;
int const * n;注意事项:
1、常量指针说的是不能通过这个指针改变变量的值,但是还是可以通过其他的引用来改变变量的值的。
int a=5;
const int* n=&a;
a=6;2、常量指针指向的值不能改变,但是这并不是意味着指针本身不能改变,常量指针可以指向其他的地址。
int a=5;
int b=6;
const int* n=&a;
n=&b;指针常量是指指针本身是个常量,不能在指向其他的地址,写法如下:
int *const n;
注意事项:
指针常量指向的地址不能改变,但是地址中保存的数值是可以改变的,可以通过其他指向改地址的指针来修改。
int a=5;
int *p=&a;
int* const n=&a;
*p=8;区分常量指针和指针常量的关键就在于星号的位置,我们以星号为分界线,如果const在星号的左边,则为常量指针,如果const在星号的右边则为指针常量。如果我们将星号读作‘指针’,将const读作‘常量’的话,内容正好符合。int const * n;是常量指针,int *const n;是指针常量。指向常量的常指针-》是以上两种的结合,指针指向的位置不能改变并且也不能通过这个指针改变变量的值,但是依然可以通过其他的普通指针改变变量的值。
const int* const p;
d、修饰函数的参数
根据常量指针与指针常量,const修饰函数的参数也是分为三种情况1、防止修改指针指向的内容void StringCopy(char *strDestination, const char *strSource);
其中 strSource 是输入参数,strDestination 是输出参数。给 strSource 加上 const 修饰后,如果函数体内的语句试图改动 strSource 的内容,编译器将指出错误。2、防止修改指针指向的地址
void swap ( int * const p1 , int * const p2 )
指针p1和指针p2指向的地址都不能修改。3、以上两种的结合。
void test(int * const p1 ,const char *strSource);
e、修饰函数的返回值
如果给以“指针传递”方式的函数返回值加 const 修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针。
例如函数const char * GetString(void);如下语句将出现编译错误:char *str = GetString();正确的用法是const char *str = GetString();
f、修饰全局变量
全局变量的作用域是整个文件,我们应该尽量避免使用全局变量,因为一旦有一个函数改变了全局变量的值,它也会影响到其他引用这个变量的函数,导致除了bug后很难发现,如果一定要用全局变量,我们应该尽量的使用const修饰符进行修饰,这样防止不必要的人为修改,使用的方法与局部变量是相同的。
三、typeof关键字
typeof 是 GNU C 扩展的一个关键字,用来获取一个变量或表达式的类型
typedef是在C和C++编程语言中的一个关键字。作用是为现有的数据类型(int、float、char……)创建一个新的名字,目的是为了使代码方便阅读和理解。
eg:
typedef struct { int x; int y;
} Point; typedef int Integer;
typedef float FloatNumber; Integer a = 10;
FloatNumber b = 3.14;
使用typeof的声明限制:
1、请注意,typeof构造中的类型名不能包含存储类说明符,如extern或static。不过允许包含类型限定符,如const或volatile。
例如,下列代码是无效的,因为它在typeof构造中声明了extern:
typeof(extern int) a;
2、下列代码使用外部链接来声明标识符b是有效的,表示一个int类型的对象。下一个声明也是有效的,它声明了一个使用const限定符的char类型指针,表示指针p不能被修改。
extern typeof(int) b;
typeof(char * const) p = “a”;
3、在宏声明中使用typeof
typeof构造的主要应用是用在宏定义中。可以使用typeof关键字来引用宏参数的类型。因此,在没有将类型名明确指定为宏实参的情况下,构造带有所需类型的对象是可能的。
下面是一个交换两个变量的值的宏定义:
#define swap(a, b) \
do {
typeof(a) __tmp = (a);
(a) = (b);
(b) = __tmp;
} while (0)
这个宏可以交换所有基本数据类型的变量(整数,字符,结构等)
四、inline关键字
内联函数的定义:
inline int Add(int a, int b) { return a + b;
}
作用:减少函数调用的开销,假如我们的程序中有一个函数会频繁的被调用,这样使程序的运行速度十分缓慢,那么我们使用内联函数,就可以解决这种问题,提高程序的运行效率.
需要注意的是,过度使用inline关键字可能导致可执行文件的体积增大。因此,在决定是否使用inline时,需要权衡代码执行效率和程序体积之间的关系。
五、extern关键字
extern 告诉编译器这个变量或函数在当前文件中是可见的,但它的实际定义(即存储分配)是在其他地方完成的。
eg:
假设你有两个源文件 file1.c 和 file2.c,以及一个头文件 shared.h。
1、修饰变量
shared.h
// 在头文件中声明一个extern变量
extern int shared_variable;
file1.c
#include "shared.h" // 定义变量
int shared_variable = 10; void functionInFile1() { // 使用变量 printf("Value of shared_variable in file1: %d\n", shared_variable);
}
file2.c
#include <stdio.h>
#include "shared.h" void functionInFile2() { // 使用变量 printf("Value of shared_variable in file2: %d\n", shared_variable);
}
2、修饰函数
shared.h
// 在头文件中声明一个extern函数
extern void shared_function();file1.c
#include <stdio.h>
#include "shared.h" void shared_function() { printf("This is a shared function.\n");
}file2.c
#include "shared.h" void functionInFile2() { // 调用在其他文件中定义的函数 shared_function();
}