为某些整数定义一个别名,可以用预处理指令#define
来完成这项工作:
#define MON 1
在此,我们定义一种新的数据类型,希望它能完成同样的工作。这种新的数据类型就是枚举类型,英文原型 enumerate v. 枚举,列举,历数。以下代码定义了这种新的数据类型 – 枚举型:
enum DAY{
MON = 1, TUE, WED, THU, FRI, SAT, SUN
};
DAY
是一个自定义的标识符,可以看成这个集合的名字,是一个可选项,即可有可无的项。#define
的替代。方法一: 枚举类型的定义与枚举类型变量的声明分开
enum DAY{
MON = 1, TUE, WED, THU, FRI, SAT, SUN
};
enum DAY goodDay; //变量 goodDay 的类型为枚举型 enum DAY
方法二: 枚举类型的定义与枚举类型变量的声明同时进行:
enum{ //跟第一个定义不同的是,此处的标号 DAY 省略,这是允许的。
jia = 0, saturday, sunday = 0, monday //每个值为:jia=0, saturday=1, sunday=0, monday=1
} workday; //变量 workday 的类型为 enum{...}
enum week { Mon = 1, Tue, Wed, Thu, Fri, Sat, Sun} days; //变量 days 的类型为枚举型 enum week
enum BOOLEAN { false, true } end_flag, match_flag; //定义枚举类型并声明了两个枚举类型的变量
方法三: 用typedef
关键字将枚举类型定义成别名,并利用该别名进行变量声明:
typedef enum wd{ //跟第一个定义不同的是,此处的标号 DAY 省略,这是允许的。
saturday, sunday = 0, monday //每个值为:saturday=0, sunday=0, monday=1
} Workday; //此处的 Workday 为枚举类型 enum{...} 的别名,注意和方法二中 workday 的区分
Workday today, tomorrow; //变量 today 和 tomorrow 的类型为枚举类型 Workday,也即 enum{...}。
typedef enum
后面的 wd
可以省略。注意: 不同的枚举类型中,不能存在同名的命名常量:
typedef enum { wed, thu, fri } Workday_1;
typedef enum { wed, sun, mon } Workday_1; //错误,Workday_1和Workday_2中定义了同名的命名常量
//使用Workday_1、Workday_2声明变量后,在给变量赋值时会造成困惑,到底赋的是哪个wed
3.1 对枚举类型的变量赋值
/*方法一:先声明变量,再对变量赋值*/
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN }; //每个元素的值为:MON=1, TUE=2, WED=3, THU=4, FRI=5, SAT=6, SUN=7
enum DAY yesterday, today, tomorrow; //声明枚举类型变量
yesterday = SAT; //对枚举型变量赋值
/*方法二:声明变量的同时赋初值*/
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };
enum DAY yesterday = SAT, today = SUN; //声明变量的同时赋初值
/*方法三:定义类型的同时声明变量,然后对变量赋值*/
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN } yesterday, today;
yesterday = SAT, today = SUN;
/*方法四:类型定义、变量声明、赋初值同时进行*/
enum DAY{
MON=1, TUE, WED, THU, FRI, SAT, SUN
} yesterday = SAT, today = SUN;
3.2 对枚举类型的变量赋整数值时,需进行强制类型转换
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN } yesterday, today;
enum DAY yesterday, today, tomorrow;
yesterday = (enum DAY) 30; //这个是允许的,强制类型转换得以使用了枚举体定义之外的值
today = 3
3.3 使用枚举类型的变量
enum{
BELL = '\a', //注意有逗号
NEWLINE = '\n' //注意没逗号
};
printf("%c %c", BELL, NEWLINE);
#include
enum escapes{
BELL = '\a',
BACKSPACE = '\b',
HTAB = '\t',
RETURN = '\r',
NEWLINE = '\n',
VTAB = '\v',
SPACE = ' '
};
enum BOOLEAN { FALSE = 0, TRUE } match_flag;
void main(){
printf("%d bytes \n", sizeof(enum escapes)); //4 bytes
printf("%d bytes \n", sizeof(escapes)); //4 bytes
printf("%d bytes \n", sizeof(SPACE)); //4 bytes
printf("%d bytes \n", sizeof(NEWLINE)); //4 bytes
printf("%d bytes \n", sizeof(FALSE)); //4 bytes
printf("%d bytes \n", sizeof(enum BOOLEAN)); //4 bytes
printf("%d bytes \n", sizeof(BOOLEAN)); //4 bytes
printf("%d bytes \n", sizeof(match_flag)); //4 bytes
printf("%d bytes \n", sizeof(0)); //4 bytes
}
运行结果如下图:
Dev c++ 配置如下图:
Dev c++ 配置如下图32-bit时,上述代码大运行结果仍不变:
原因:
不论是 32 位环境还是 64 位环境,c/c++ 都为整型数字字面值常量分配 4 字节空间。
可以类比:不论是 32 位环境还是 64 位环境,c/c++ 都为 int 分配 4 字节空间。
.i
作为文件扩展名。.i
文本文件翻译成.s
文本文件。.s
文件包含了汇编语言程序,汇编语言程序以一种标准的文本格式确切描述一条低级机器语言指令。.s
文件翻译成机器语言指令,并打包成可重定位目标程序,一般以.o
作为文件扩展名。可重定位目标程序是二进制文件,它的字节编码是机器语言指令而不是字符。.o
目标文件组合起来,创建可执行目标文件。.bss
段。未初始化的全局变量和未初始化的静态变量在相邻的.data
。const
、#define
、char* ptr = "blabla"
中的blabla
等数据常量放在.rodata
段。int main()
{
char s[] = "abc123"; //栈
char* p = "abc123"; // abc123\0 在常量区,p在栈上。
}
1、由于两者都是局部变量,所以都是动态存储区内的变量。
2、char s[]
的含义是一个char类型的数组,只是缺省了长度,这个长度将由编译器以赋值的内容来推断。所以这句话相当于char s[7] = "abc123"
,所以是在栈上的。
3、char* p
是一个char类型的指针变量,这个指针指向了一个常量的字符串。常量在常量存储区的.rodata
段。而指针变量因为其是局部变量所以是在栈上的。
详解c语言中的static关键字
概念:c语言中的static
关键字有三种用途:用于修饰局部变量、全局变量和函数,修改其数据存储类型
static
修饰的局部变量就是静态局部变量, 编译阶段就已经被分配了内存空间,程序员不初始化,则会被默认初始化为0,存放于静态存储区,函数返回时值保持不变,出函数不销毁,下一次进入函数依然存在。extern
外部声明后可以直接使用。extern
也没用。其它文件可以定义与其同名的变量,两者互不影响。在定义不需要与其它文件共享的全局变量时,加上static
关键字能够有效降低程序模块之间的耦合,避免不同文件同名变量的冲突,且不会误使用。static
,就是静态函数。例如static int main()
。详解c++中的static关键字
static
的对象将分配到静态存储区,并且一直作用到程序结束。静态对象也使用和其它普通对象一样的构造函数进行初始化。但是使用static
关键字默认初始化为0仅适用于原始数据类型,不适用于用户自定义的数据类型。class Abc{
int i;
public:
Abc(){
i=0;
cout << "constructor";
}
~Abc(){
cout << "destructor";
}
};
void f(){
static Abc obj;
}
int main(){
int x=0;
if(x==0){
f();
}
cout << "END";
}
static
关键字的输出2:if
条件范围结束时不调用析构函数来销毁obj
对象,这是因为输出1对应的对象obj
是静态的,其作用于程序的整个生命周期,因此在main()
函数退出时才调用obj
对象的析构函数。volatile应该解释为“直接存取原始内存地址中的value”比较合适,“易变的”这种解释简直有点误导人;
1)并行设备的硬件寄存器(如:状态寄存器)
2)一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3)多线程应用中被几个任务共享的变量
一般说来,volatile用在如下的几个地方:
1、中断服务程序中修改的供其它程序检测的变量需要加volatile;
2、多任务环境下各任务间共享的标志应该加volatile;
3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;
另外,以上这几种情况经常还要同时考虑数据的完整性(相互关联的几个标志读了一半被打断了重写),在1中可以通过关中断来实现,2中可以禁止任务调度,3中则只能依靠硬件的良好设计了。
1、头文件中写入函数的声明即可。#ifdef
、#define
为条件编译,是为了防止函数被重定义。
2、
①编译阶段分配内存
②所有对象共享同一份数据
③类内声明,类外初始化
class Base
{
public :
static int m_A; //类内声明
};
int Base::m_A = 100; //类外初始化
动态多态需满足的条件:
①有继承关系
②子类重写父类的虚函数
class Animal
{
public :
virtual void speak() //Speak函数就是虚函数。函数前面加virtual关键字,就成了虚函数,那么编译阶段就不能确定函数调用了。
{cout << "动物在说活。" << endl;}
};
class Cat : public Animal
{
public :
void speak() //子类重写父类函数
{cout << "小猫在说话。" << endl;}
};
动态多态的使用:
父类的指针或引用 指向子类对象
class Cat :public Animal //父类Animal的Cat子类
{
public:
void speak()
{cout << "小猫在说话" << endl;}
};
class Dog :public Animal //父类Animal的Dog子类
{
public:
void speak()
{cout << "小狗在说话" << endl;}
};
void DoSpeak(Animal & animal) //父类的引用
{
animal.speak();
}
void test01()
{
Cat cat; //子类对象
DoSpeak(cat); //父类的引用指向子类对象
Dog dog; //子类对象
DoSpeak(dog); //父类的引用指向子类对象
}
封装
继承
多态
字符串对比主要用于比较两个字符串是否相等,判断谁大谁小的意义并不是很大
string str1 = "hello";
string str2 = "hell0";
str1.compare(str2); //返回值 相等(0),大于(1),小于(-1).
栈不允许遍历行为 (STL的栈符合先进后出原则)
可以判断栈容器是否为空吗? 可以 empty
栈容器可以返回元素个数吗? 可以 size (可以在压栈的时候计数)
编译器的自动生成是够用的,但是仍然要写一个,否则多态的delete会出问题。
i < top, i 就取到 top-1,
i <= top, i 就取到 top
for(int i=0; i<top; i++)
for(int i=0; i<=top; i++)
不空字符
空一个字符
不空字符
空半个字符
提示:这里描述项目中遇到的问题:
例如:数据传输过程中数据不时出现丢失的情况,偶尔会丢失一部分数据
APP 中接收数据代码:
@Override
public void run() {
bytes = mmInStream.read(buffer);
mHandler.obtainMessage(READ_DATA, bytes, -1, buffer).sendToTarget();
}