一、位运算
符号 | 运算规则 |
---|---|
&(与) | 两个位都为1时,结果才为1(从真假方面看,只有当两个位都为真时,结果才为真) |
\(或) | 两个位都为0时,结果才为0 (从真假方面看,如果两个运算对象中相应的一个位为真或者两个位都为真,那么结果为真) |
^(异或) | 两个位相同为0,相异为1(从真假方面看,如果两个运算对象中相应的一个位为真且不是两个位同为1,那么结果为真) |
~(取反) | 0变1,1变0 |
<< (左移) | 各二进位全部左移若干位,高位丢弃,低位补0 |
>>(右移) | 各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移) |
掌握了这六种操作否的用法,C语言的位操作就差不多了。这六种操作符的解释如下:
1、 & 按位与: 如果两个相应的二进制位都为1,则该位的结果值为1,否则为0。
例如: 1&1 = 1 1&0 = 0 0&1 = 0 0&0 = 0
2、| 按位或:两个相应的二进制位中只要有一个为1,该位的结果值为1。
例如: 1|1 = 1 0|1 = 1 1|0 = 1 0|0 = 0
3、^ 按位异或: 若参加运算的两个二进制位值相同则为0,否则为1。
例如: 1^1 = 0 0^1 = 1 1^0 = 1 0^0 = 0
4、~ 取反: 对一个二进制数按位取反,即将0变1,将1变0。
例如: 1! = 0 0! = 1
5、<< 左移:用来将一个数的各二进制位全部左移N位,右补0。
例如: 00001100 << 2 = 00110000
6、>> 右移:将一个数的各二进制位右移N位,移到右端的低位被舍弃,对于无符号数,高位补0。
例如: 00001100 >> 2 = 00000011
二、静态变量(static)
static最主要有以下两点用途:
1、让一个变量长期有效,而不管其是在什么地方被申明。
例如:
int fun1()
{
static int s_value = 0;
….
}
fun1不管在什么地方被调用,当函数退出后,s_value最后的值将一直会被系统保存,下次s_value再被用到时,也即当fun1()再次被调用时,s_value初始值将是最近被保存过的值(请注意s_value初始化操作只会被执行一次,即上述s_value =0 这个语句)。
2、避免多个文件使用了相同的变量名而导致冲突 。
在C语言中static的作用如下:
第一、在修饰变量的时候,static修饰的静态局部变量只执行一次,而且延长了局部变量的生命周期,直到程序运行结束以后才释放;
第二、static修饰全局变量的时候,这个全局变量只能在本文件中访问,不能在其它文件中访问,即便是extern外部声明也不可以;
第三、static修饰一个函数,则这个函数的只能在本文件中调用,不能被其他文件调用。Static修饰的局部变量存放在全局数据区的静态变量区。初始化的时候自动初始化为0。
static int st_val; //静态全局变量 -- 静态存储区
int ex_val; //全局变量 -- 静态存储区int main(void)
{
int a = 0; //局部变量 -- 栈上申请
int *ptr = NULL; //指针变量
static int local_st_val = 0; //静态变量
local_st_val += 1;
a = local_st_val;
ptr = (int *)malloc(sizeof(int)); //从堆上申请空间
if(ptr != NULL)
{
printf("*p value:%d", *ptr);
free(ptr);
ptr = NULL;
//free后需要将ptr置空,否则会导致后续ptr的校验失效,出现野指针
}
}
C语言的作用域不仅描述了标识符的可访问的区域,其实也规定了变量的存储区域,在文件作用域的变量st_val和ex_val被分配到静态存储区,其中static关键字主要限定变量能否被其它文件访问,而代码块作用域中的变量a, ptr和local_st_val则要根据类型的不同,分配到不同的区域,其中a是局部变量,被分配到栈中,ptr作为指针,由malloc分配空间,因此定义在堆中,而local_st_val则被关键字限定,表示分配到静态存储区,这里就涉及到重要知识点,static在文件作用域和代码块作用域的意义是不同的:在文件作用域用于限定函数和变量的外部链接性(能否被其它文件访问), 在代码块作用域则用于将变量分配到静态存储区。
静态变量常用使用方式:
定义局部变量:用static声明后的局部变量的值在函数调用结束后不消失而保持原值,其占用的是静态存储区,所以即其占用的存储单元不释放。典型应用是用static变量求阶乘n!。
// 求阶乘 n!
int fac(int)
{
static int f = 1 ;
f = f * n ;
return f ;
}
main()
{
int i ,n ;
float sum;
scanf("%d",&n) ;
for(i = 1 ;i <= n ;i++)
{
sum = fac(i) ;
}
printf("输出%d!= %f ",n,sum) ;
}
三、extern变量声明
C 语言中 extern 可以置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。这里面要注意,对于 extern 申明变量可以多次,但定义只有一次。
例如:
extern u16 USART_RX_STA;
这个语句是申明 USART_RX_STA 变量在其他文件中已经定义了,在这里要使用到。
四、关键字const
const int a; //整型常数
int const a; //整型常数
const int *a; //指向整型常数的指针(整型常数不能修改,指针可以)
int * const a; //指向整型数得常指针(指针指向的整型数可以修改,指针不能修改)
int const * a const; //指向整型常数的常指针(指针指向的整型数不能修改,同时指针也不能修改)
前两个的作用是一样,a是一个常整型数。第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。第四个意思 a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。
const关键字注意:
1、const关键字修饰的变量可以认为有只读属性,但它绝不与常量划等号。
例如:
const int i=5;
int j=0;
...
i=j; //非法,导致编译错误,因为只能被读
j=i; //合法
2、const关键字修饰的变量在声明时必须进行初始化。
例如:
const int i=5; //合法
const int j; //非法,导致编译错误
3、C标准中,const定义的常量是全局的。