常量和变量
常量
- 在程序执行过程中值不会发生变化的量。
整型常量
- 整型数,例如:1,10,20,100
- 整型字面值如:123,10,-20。默认情况下如是int类型。
- 如果要显示的指定整型常量为其它类型,要在其后面添加后缀。指定整型常量为long类型时,要在后面加上l或者L,例如:12L,19l。
- 指定整型常量为long long类型时,要在后面加上ll或者LL,例如:38LL,100LL。
浮点型常量
- 浮点型数字,例如:3.14,1.99
- 浮点型字面值如:3.14159,1.2,5.9。默认情况下是double类型。
- 与整型常量类似,指定浮点型常量为float类型,要在后面加上f或F。例如:1.23f,3.14F,1.0f。
- 指定浮点型常量为long double类型,要在后面加上l或者L。例如:12.7L。
- 除了使用小数点表示浮点型外,还可以使用E表示法。比如:0.618可以表示为6.18E-1,6000000可以表示为6E+6。
字符常量
- 由单引号引起来的单个的字符或转义字符,例如:'a','b','\n','\t'
- 反斜杠后跟随三个字符表示三位八进制。'\015'这是一个字符。原型:\ddd
- 反斜杠后跟随x和两位字符表示两位十六进制。'\x7F'这是一个字符。原型:\xhh
- 以上8进制和16进制都代表着【一个字节大小的整数值字符】(一个字节8位)。
-
都是单个字符,都是一个字节八位。
-
字符串常量
-
由双引号引起来的一个或多个字符组成的序列。
标识常量
- 宏定义只是单纯的宏体替换宏名,不进行语法检查,一改全改。
- 其占用编译时间,不占用运行时间。
-
宏定义的内容是常量,不可改变。
-
#define
基本示例 -
#define
优先级易错示例 -
#define
带参宏示例 -
#define
在标准c中无解的带参宏#include <stdio.h> #define MAX(i, j) ((i) > (j) ? (i) : (j)) int main(void) { int i = 3, j = 4; printf("i = %d\tj = %d\n", i, j); printf("max = %d\n", MAX(i++, j++)); printf("i = %d\tj = %d\n", i, j); return 0; } /* 执行结果: i = 3 j = 4 max = 5 i = 4 j = 6 比较发现,j的值经过自增为6,比预期 +1。原因是,替换后的结果是: ((i++) > (j++) ? (i++) : (j++)) 那么较大的值一定在后面又自增了一次。 */
-
gcc拓展了标准c的宏的使用
// 以下gcc拓展部分,在gcc、clang中编译通过,msvc不支持。 // typeof clan中 \Wall 给出警告,mscv不支持。 // clang 中 \Wall 下将给出警告:-Wgnu-statement-expression-from-macro-expansion // (warning: use of GNU statement expression extension from macro expansion 从宏扩展中使用 GNU 语句表达式扩展) #include <stdio.h> #define MAX(a, b) ({int A = a, B = b; ((A) > (B) ? (A) : (B));}) // #define MAX(a, b) ({typeof(a) A = a, B = b; ((A) > (B) ? (A) : (B));}) int main(void) { int i = 3, j = 4; printf("i = %d\tj = %d\n", i, j); printf("max = %d\n", MAX(i++, j++)); printf("i = %d\tj = %d\n", i, j); return 0; } /* 执行结果: i = 3 j = 4 max = 4 i = 4 j = 5 这样的表达下,较大的值不会出现两次自增 */
变量
-
用来保存一些特定的内容,并且在程序执行过程中值随时发生变化的量。
-
定义:
-
标识符:由字母、数字、下划线组成且不能以数字开头的一个标识序列。
-
写标识符尽量做到见名知意
-
数据类型:基本数据类型 或 构造类型
-
存储类型:auto(自动) static(静态型) register(建议型) extern(说明型)
- auto:默认,自动分配空间,自动回收空间。auto自动变量,存储在stack(栈)中,函数内有效,函数结束时自动销毁。初始值是随机分配的。
- register:(建议型)寄存器类型,只能定义局部变量,不能定义全局变量;大小有限制,只能定义32位大小的数据类型。如果double就不可以,寄存器没有地址,所以一个寄存器类型的变量无法打印地址查看或使用。
- static:(静态型)自动初始化为0或空值,并且其变量的值有继承性。另外,常用于修饰变量或函数。
- extern:(说明型)意味着不能改变说明变量的值或类型。
-
变量的生命周期和作用范围
- 全局变量的作用域从定义的地方开始,直到当前程序结束。
- 局部变量从当前定义位置开始到所在的块结束。
- 代码在大括号中时是一个语句体,这个代码块有局部作用域。
变量的存储类型示例表格
局部变量 | 局部变量 | 局部变量 | 外部变量 | 外部变量 | |
---|---|---|---|---|---|
存储类别 | auto | register | 局部 static | 外部 static | 外部 |
存储方式 | 动态 | 动态 | 静态 | 静态 | 静态 |
存储区 | 动态区 | 寄存器 | 静态存储区 | 静态存储区 | 静态存储区 |
生存期 | 函数调用开始至结束 | 函数调用开始至结束 | 程序整个运行期间 | 程序整个运行期间 | 程序整个运行期间 |
作用域 | 定义变量的函数或复合语句内 | 定义变量的函数或复合语句内 | 定义变量的函数或复合语句内 | 本文件 | 其他文件 |
赋初值 | 每次函数调用时 | 每次函数调用时 | 编译时赋初值,只赋值一次 | 编译时赋初值,只赋值一次 | 编译时赋初值,只赋值一次 |
未赋初值 | 不确定 | 不确定 | 自动赋初值0或空字符 | 自动赋初值0或空字符 | 自动赋初值0或空字符 |
- 局部变量默认为 auto 类型
- register 型变量个数受限,且不能为 long、double、float 型
- 局部 static 变量具有全局寿命和局部可见性
- 局部 static 变量具有可继承性
- extern 不是变量定于,可拓展外部变量作用域
变量的使用示例
-
auto 类型变量示例
#include <stdio.h> void func(void) { auto int x = 0; x += 1; printf("%p -> %d\n", &x, x); } int main(void) { func(); func(); func(); return 0; } /* 执行结果: 000000B8A9CFF594 -> 1 000000B8A9CFF594 -> 1 000000B8A9CFF594 -> 1 */
- 上述代码执行后,因为函数内使用auto,所以函数结束即释放,每次都是新的变量x。
-
static 类型变量示例(一):变量定义一次,下次不会生成新的地址空间。
#include <stdio.h> void func(void) { static int x = 0; x += 1; printf("%p -> %d\n", &x, x); } int main(void) { func(); func(); func(); return 0; } /* 执行结果: 00007FF6677EC1B4 -> 1 00007FF6677EC1B4 -> 2 00007FF6677EC1B4 -> 3 */
- 上述代码执行后,因为函数内使用static,第一次x定义并赋值后,下次不会再生成新的地址空间,x的值每次自增;并且地址一定是相同的。
-
static 类型变量示例(二):修饰变量或函数,static 修饰的变量或函数只能在本文件范围,类似访问控制。
/* MSVC 编译环境 - 包含文件 main.c tools.c tools.h */ /* ---------- main.c ---------- */ #define _CRT_SECURE_NO_WARNINGS #include "tools.h" int numbers = 10; int main(void) { printf("[%s] numbers = %d\n", __FUNCTION__, numbers); call_test_func(); printf("[%s] numbers = %d\n", __FUNCTION__, numbers); return 0; } /* ---------- tools.h ---------- */ #ifndef TOOLS #define TOOLS #include <stdio.h> #include <stdbool.h> #include <math.h> void call_test_func(void); static void test_func(void); #endif // !TOOLS /* ---------- tools.c ---------- */ #include "tools.h" static void test_func(void) { extern int numbers; numbers += 1; printf("[%s] numbers = %d\n", __FUNCTION__, numbers); } void call_test_func(void) { printf("RUN IN [%s]\n", __FUNCTION__); test_func(); } /* 执行结果 [main] numbers = 10 RUN IN [call_test_func] [test_func] numbers = 11 [main] numbers = 11 */
- 使用 static 可以隔离不同文件中同名的全局变量。
- 进行访问控制。
-
extern 类型变量示例
/* MSVC 编译环境 - 包含文件 main.c tools.c tools.h */ /* ---------- main.c ---------- */ #define _CRT_SECURE_NO_WARNINGS #include "tools.h" int numbers = 10; int main(void) { printf("[%s] numbers = %d\n", __FUNCTION__, numbers); test_func(); printf("[%s] numbers = %d\n", __FUNCTION__, numbers); return 0; } /* ---------- tools.h ---------- */ #ifndef TOOLS #define TOOLS #include <stdio.h> #include <stdbool.h> #include <math.h> void test_func(void); #endif // !TOOLS /* ---------- tools.c ---------- */ #include "tools.h" void test_func(void) { extern int numbers; numbers += 1; printf("[%s] numbers = %d\n", __FUNCTION__, numbers); } /* 执行结果 [main] numbers = 10 [test_func] numbers = 11 [main] numbers = 11 */
- tools.c 中 extern 声明了变量 numbers 在外部。
- numbers 要使用全局变量。
- extern 声明时不允许修改外部变量的值(不允许对外部变量的局部声明使用初始值设定项)。