宏常量详解
// 宏常量与const常量的区别
1、发生时机不同:前者在预处理阶段,后者在编译阶段
2、类型检查:宏定义没有类型检查、语法检测,只是在预处理阶段做了简单的文本替换,虽然也有编译阶段,但是在编译阶段不报错,将报错的时机延迟到了。const常量是有类型检查、语法检测的,更安全
带参宏函数
// define.c
#define max(a, b) ((a) > (b) ? (a) : (b))
#define MAX(a, b) ({ int A = a; int B = b; ((A) > (B) ? (A) : (B));})
void test1()
{
int i = 5;
int j = 3;
printf("i = %d, j = %d\n", i, j);
printf("max = %d\n", max(i++, j++));
printf("i = %d, j = %d\n", i, j);
}
// 输出结果
i = 5, j = 3
max = 6
i = 7, j = 4 // 较大者i,自增了2次
void test2()
{
int i = 5;
int j = 3;
printf("i = %d, j = %d\n", i, j);
printf("MAX = %d\n", MAX(i++, j++));
printf("i = %d, j = %d\n", i, j);
}
// 输出结果
i = 5, j = 3
MAX = 5
i = 6, j = 4 // 结果正确
int main()
{
test1();
test2();
return 0;
}
// gcc -E define.c,查看预处理后的源文件
void test1()
{
int i = 5;
int j = 3;
printf("i = %d, j = %d\n", i, j);
printf("max = %d\n", ((i++) > (j++) ? (i++) : (j++)));
printf("i = %d, j = %d\n", i, j);
}
void test2()
{
int i = 5;
int j = 3;
printf("i = %d, j = %d\n", i, j);
printf("MAX = %d\n", ({ int A = i++; int B = j++; ((A) > (B) ? (A) : (B));}));
printf("i = %d, j = %d\n", i, j);
}
// 宏定义#define:是预处理阶段,占用编译时间,一改全改
// 不检查语法,只是单纯的完成宏体与宏名的替换
// 宏是标识常量,不可做左传
// 函数:编译阶段,占用运行时间
常量概念
- 常量:在程序运行期间其值不发生改变的量
- 常量表达式:在编译期间可直接求值的表达式
- 常量表达式可以用于指定数组长度,用于switch中的case N
#define N 5 // 常量表达式
const int N = 5; // 常量,不是常量表达式
C语言中的const
- const修饰的全局变量保存在常量区,不可通过任何方式改变其值
- const修饰的全局变量链接属性为外部链接属性
- const修饰的局部变量保存在栈区,不可通过变量名直接其值,却可通过其地址间接修改其值
- const变量只是只读变量,不算真正的常量
- const变量有它自己的内存空间
C++中的const
- const修饰的全局变量保存在常量区,不可通过任何方式修改其值
- const修饰的全局变量默认为内部链接属性
- const修饰的局部变量保存在符号表,且无法取得符号表地址
- 取const修饰的局部变量的地址时,编译器会产生一个临时变量保存该地址值
- const对象一理创建后其值便不能再修改,故const对象必须在创建时初始化
- 只能在const对象上对其执行不改变其值的操作
符号表
- 符号表是编译器在编译过程中产生的关于源程序语法符号的数据结构
- 变量名、变量名表、数组名、数组名表等都与之类似
- 符号表是编译器内部自用的数据结构,程序员不可用
- 符号表不会进行最终的待执行文件中,它只与编译器有关
- 进入符号表的量有
- 只有用字面值初始化的const常量才会进入符号表
- 对const常量引用会导致编译器为其分配存储空间
- volatile修饰的const常量只会退化为只读常量,不会进入符号表