1、register
register:请求编译器尽可能地将变量存在CPU内部寄存器中;
使用注意:
register修饰变量的类型必须是CPU所接受的;
register变量可能不是在内存中存储,所以不能使用&来获取变量的地址
2、Static
全局静态变量:作用范围局限于它的源文件,即只有本文件内的代码才可以访问它,变量名在其他文件内不可见
局部静态变量:局限于特定函数,但出作用域并不释放,在函数体内的静态变量的值也能够维持
静态函数:作用范围仅限于它的源文件,即只有本文件内才能够调用,函数名在其他文件不可见
存放位置:程序开始时,存放在全局数据区,结束时释放空间,默认初始化值是0,使用时可改变其值;
例:
void f(int c)
{ int a=0;
static int b=0;
a++;
b++;
printf("%d: a=%d, b=%d\n", c, a, b);
}
void main( )
{ int i;
for (i=1; i<=3; i++)
f( i );
}
1: a=1, b=1
2: a=1, b=2
3: a=1, b=3
3、const只读变量
const int* a; int const *a;
是一个指向const int型的指针,a所指向的内存单元不可改写,所以(*a)++是不允许的,但a可以改写,所以a++是允许的。
int* const a;
a是一个指向int型的const指针,*a是可以改写的,但a不允许改写。
int const * const a;
a是一个指向const int型的const指针,因此*a和a都不允许改写
const给读代码的人传达非常有用的信息。比如一个函数的参数是const char *,你在调用这个函数时就可以放心地传给它char *或const char *指针,而不必担心指针所指的内存单元被改写。
尽可能多地使用const限定符,把不该变的都声明成只读,这样可以依靠编译器检查程序中的Bug,防止意外改写数据。
const对编译器优化是一个有用的提示,编译器也许会把const变量优化成常量
3、volatile
作用:不会在两个操作之间把volatile变量缓存在寄存器中;不做常量合并与常量传播等优化;对voiatile变量的读写不会被优化掉。
中断服务程序中修改的供其他程序检测的变量,多任务环境下各任务间共享的标志,存储器映射的硬件存储器要加volatile说明。
4、extern外部变量声明
表明变量或函数的定义在别的文件中,下面用到的这些变量或是函数是外来的,不是本文件定义的,提示编译器遇到此变量或函数时,在其他模块中寻找定义;
如果一个函数只能被本文件中其它函数所调用,称为内部函数(或静态函数)。定义时在函数类型前加static。
6、struct定义结构体
在网络协议、通信控制、嵌入式系统的C/C++编程中,我们经常要传送的不是简单的字节流(char型数组),而是多种数据组合起来的一个整体,其表现形式是一个结构体。
struct node
{
char a;
short b;
char c;
};
struct node link;
int count = sizeof(link);
printf(“%d\n”,count);
结果是多少?Count=4;
#include <stdio.h>*
struct A
{
int iMember;
char *cMember;
};
int main(int argc, char* argv[])
{
struct A instant1,instant2;
char c = 'a';
instant1.iMember = 1;
instant1.cMember = &c;
instant2 = instant1;
printf(“instant1.cMember = %c”,*(instant1.cMembe));
*(instant2.cMember) = 'b';
printf(“instant2.cMember = %c”,*(instant2.cMembe));
printf(“instant1.cMember = %c”,*(instant1.cMembe));
return 0;
}
① “结构体名”用作结构体类型的标志;
②花括弧内是该结构体中的各个成员,由它们组成一个结构体;在结构体内对各成员都应进行类型声明;
③“成员表列”也称为域表。每个成员也称为结构体中的一个域,成员名命名规则与变量名一样;
④每个成员名前的类型标识符可以为已经定义了的任意类型,当然可以是结构体类型标识符,即结构体成员也可以是另一个结构体变量。
⑤此处只是构造出一个新的类型,并没有定义该类型的变量,因此在内存中并没有开辟任何存储空间;
⑥在程序中可以定义多个结构体类型,不同结构体类型用不同的结构体名来区分。
结构体类型定义描述结构的组织形式,不分配内存;用指针,成员只能是指向本结构体类型的指针变量,不能指向其他结构体。
引用形式:“.”是成员运算符,在所有的运算符中优先级最高。
struct student
{ int num;
char name[20];
float score;
}stu1, stu2;
stu1.num=10001;
stu1.score=95;
stu1.name ="Li Ming";错=》strcpy(stu1.name, "Li Ming");
不能将一个结构体变量作为一个整体进体输入输出,只能对结构体中的各个成员分别进行输入输出。
printf("%d%s%f", stu1);scanf("%d%s%f", &stu1);错
printf("%d%s%f", stu1.num, stu1.name, stu1.score);
scanf("%d", &stu1.num);gets(stu1.name);
指向结构体变量指针的定义:
struct student
{ int num;
char name[20];
float score;
};
struct student stu, *p;
p=&stu;p中存放着结构体变量stu在内存中的首地址
注意:不能用指向结构体变量的指针指向该结构体变量的某个成员。
p=&stu.num;错
int *ip;
ip=&stu.num;
访问结构体成员变量的三种方法:
①、stu.num、stu.name、stu.score
②、(*p).num、(*p).name、(*p).score
③、p->num、p->name、p->score
说明:①、“->”为指向运算符,是优先级最高的运算符;
②、成员运算符“.”的优先级高于指针运算符“*”,因此采用 “(*p).成员名” 形式时,括号不能省略;
③、注意以下几种运算:
p->num 得到p指向的结构体变量中的成员num的值
p->num++ 得到p指向的结构体变量中的成员num的值,用完后该值加1
++p->num 使p指向的结构体变量中的成员num的值加1
在定义结构体变量的同时,可以进行初始化。
注意:结构体变量的各个初值用花括号{、}括起来,大括号内各个成员变量的值之间用逗号分隔,其值必须与成员变量一一对应,且数据类型应与成员变量一致。
struct student
{ int num;
char name[20];
char sex;
int age;
char addr[30];
}stu1={112,“Wang Lin”,‘M’,19, “200 Beijing Road”};
嵌入式系统开发中可以使用如下方式对结构体变量进行初始化:
struct student
{ int num;
char name[20];
char sex;
int age;
char addr[30];
};
Struct student stu1=
{ .num = 112,
.name=“Wang Lin”,
.sex=‘M’,
.age=19,
.addr=“200 Beijing Road”};
该赋值方式在花括号外无效!!!!
结构体数组的初始化
struct 结构体类型标识符
{
类型标识符1 成员名1;
类型标识符2 成员名2;
…… ……
类型标识符n 成员名n;
}结构体数组={ {数组元素0的各个初值},
{数组元素1的各个初值},
……};
struct student
{ int num;
char name[20];
float score;
}stu[ ]={{10101,"Li Ming", 88},{10102,"Zhang Jin",92},
{10103, "Wang Lin", 98.5}};
数组中各个元素的初值用大括号{、}括起来,同一数组元素的各个成员变量的初值用逗号分隔。
struct student
{ int num;
char name[20];
float score;
}stu[ ]=
{
{.num=10101, .name="Li Ming", .score=88},
{.num=10102, .name="Zhang Jin", .score=92},
{.num=10103, .name="Wang Lin", .score=98.5}
};
使用结构体存在的问题: 内存空洞 字对齐 半字对齐
struct node
{char ch;
int num;
}; 变量占8个字节
struct node
{char ch;
int num;
char ch1;
}; 变量占12个字节
struct node
{char ch;
char ch1;
char ch2
}; 变量占3个字节
int型变量占四个字节 字对齐
后一个变量若能在前一个变量分配的空间中存放下,则后一个变量不再重新分配空间。
struct node
{char ch;
short num;
char ch1;
short b;
}; 变量占10个字节
short型变量占2个字节 半字对齐
减少内存空洞的方法:同类型的成员定义放在一起!
7、union
当多个基本数据类型或复合数据结构要占用同一片内存时,我们要使用联合体;
当多种类型,多个对象,多个事物只取其一时(我们姑且通俗地称其为“n 选1”),我们也可以使用联合体来发挥其长处;
有时候需要将几种不同类型的变量存放到同一段内存单元中。
分配空间字对齐!4的整数倍!
union node
{ char ch[7];
int num;
}; 占8字节!
可以把一个整型变量、一个字符型变量、一个实型变量放在同一个地址开始的内存单元中。即使几个不同的变量共占同一段内存空间。
所谓“共用体(union)”是指使几个不同的变量共占同一段内存的数据类型。
CPU存取数据都是从低地址开始开始存放,一个变量占用的内存空间往往不止一个字节,但是不同类型的CPU存放数据的顺序不同,因而产生了字节序的概念,按存放顺序的不同分为大端字节序和小端字节序两种:
Big_endian 大端字节序: 数据的高字节位存储在低地址对应的存储单元;
Little_endian 小端字节序:数据的低字节位存放在低地址对应的存储单元。
8、enum
枚举类型声明代表常量的符号名称。
enum的默认值
enum kids{nippy, slats, skippy, nina ,liz};
enum的指定值
enum levels {low=100,medium=500,high=2000};
enum的用法
作为switch的标签
9、typedef
typedef是C语言的关键字,其作用是为一种数据类型定义一个新名字
格式:typedef 数据类型 自定义数据类型
typedef unsigned long uint32;
在嵌入式的开发中,由于涉及到移植问题,typedef的功能就更引人注目了。