(1) bool类型
(2)const限定符
(3)const与#define
(4)结构体内存对齐
1、bool类型
1)逻辑类型也称布尔类型,其取值为true(逻辑真)和false(逻辑假),存储字节数在不同编译系统中可能有所不同,VC++中为1个字节。
2)声明方式:bool result;
result = true;
3)可以当做整数用(true一般为1,false为0)
4)把其它类型的值转换为布尔值时,非零值转换为true,零值转换为false。
例子:
int main(void) { bool result; //result = true; result = 100; //warning C4305: “=”: 从“int”到“bool”截断 cout << result << endl; return 0; }
2、const限定符
1)用const给字面常量起个名字(标识符),这个标识符就称为标识符常量;因为标识符常量的声明和使用形式很像变量,所以也称常变量
2)定义的一般形式:
const 数据类型 变量名 = 常量值;
数据类型 const 常量名 = 常量值;
例如:const float PI = 3.14159f;
3)注意事项:
常变量在定义时必须初始化;
常变量初始化之后,不允许再被赋值;
#include <iostream> using namespace std; int main(void) { //const int a; Error,常量必须初始化 const int a = 100; //a = 200; Error,常量不允许重新被赋值 const int* p; //将p看成一个变量,变量类型是一个指向整型常量的指针变量。 //或者这样记:const在*的左边,表示*p为常量,经由*p不能更改指针所指向的内容。这里const和int可以互换。 int b = 22; p = &b; //*p = 200; ERROR,常量不能重新被赋值 //int* const p2; Error ,p2为常量,常量必须初始化, int* const p2 = &b; //const在*右边,表示p2为常量 //int c = 100; //p2 = &c; ERROR,常量不能重新被赋值 *p2 = 200; cout << *p2 << endl; return 0; }
3、const与#define
1)const定义的常量与#define定义的符号常量的区别
$ const定义的常量又类型,而#define定义的没有类型,编译可以对前者进行类型安全检查,而后者仅仅只是做简单替换。
$ const定义的变量在编译时分配内存,而#define定义的常量是在预编译时进行替换,不分配内存。
$作用域不同,const定义的常变量的作用域为该变量的作用域范围,而#define定义的常变量作用域为它的定义点到程序结束。当然也可以在某个地方用#undef取消。
$定义常量还可以用enum,尽量用const,enum替换#define定义常量。
2)高层次:const enum inliine 替换define
在底层编程:#define 是很灵活的。
#include <iostream> using namespace std; #define STR(a) #a //将STR(a)替换成#a #define CAT(a,b) a##b int main(void) { int xy = 100; cout << STR(ABCD) << endl; //#ABCD <=> "ABCD" cout << CAT(x, y) << endl; //x##y <=> xy return 0; } /* 输出结果: ABCD 100 */
3)#define定义的常量,容易产生副作用。
#include <iostream> using namespace std; //Effective C++3rd的一个例子 #define CALL_WITH_MAX(a,b) (a) > (b) ? (a) : (b) int main(void) { int a = 5; int b = 0; CALL_WITH_MAX(++a, b); //a被累加二次 CALL_WITH_MAX(++a, b + 10); //a被累加一次 cout << a << endl; cout << b << endl; return 0; } /* * 在这里,调用f之前,a的递增次数竟然取决于“它被拿来和谁比较” */
4)定义常量还可以用enum,尽量用const、enum替换#define定义常量。
4、结构体内存对齐
1)什么是内存对齐?
¥ 编译器为每个“数据单元”安排某个合适的位置。
¥ C、C++语言非常灵活,它允许你干涉“内存对齐”
2)为什么要对齐?
¥ 性能原因:在对齐的地址上访问数据更快。
3)如何对齐?
¥第一个数据成员放在offset为0的位置。
¥其它成员对齐至min(sizeof(member)),#pragma pack 所指定的值)的整数倍。
¥整个结构体也要对齐,结构体总大小对齐至各个成员中最大对齐数的整数倍。
#include <iostream> #include <cstdio> using namespace std; //#pragma pack(4) 此语句可以用于更改对齐数。 struct Test { char a; double b; }; //第一个成员与结构体变量的偏移量为0 //其它成员要对齐到某个数字(对齐数)的整数倍的地址。 //对齐数取编译器预设的一个对齐整数与该成员大小的较小值,在vs2019中预设的默认值为8个字节。 //结构体总大小为最大对齐数的整数倍。 int main(void) { Test test; //&test = &test.a; char* p = (char*)&test; printf_s("p = %p\n",p); p = &test.a; printf_s("p = %p \n",p); cout << sizeof(Test) << endl; return 0; } /* 输出: p = 00CFFCA8 p = 00CFFCA8 16 */