C常量
常量是固定值,在程序执行期间不会改变。这些固定值,又叫字面量。
常量可以是任何的基本数据类型,比如整数常量、浮点常量、字符常量、或字符串字面值,也有枚举常量。
常量就像是常规的变量,只不过常量的值在定义后不能进行修改。
整数常量
整数常量可以是十进制、八进制或十六进制的常量。前缀指定基数:0x或0X表示十六进制,0表示八进制,不带前缀则默认表示十进制。
整数常量也可以带一个后缀,后缀是U和L的组合,U表示无符号整数,L表示长整数。后缀可以是大写,也可以是小写,U和L的顺序任意。
下面列举几个整数常量的实例:
212 //合法的
215u //合法的
0xFeeL //合法的
078 //非法的:8不是八进制数字
032UU //非法的:不能重复后缀
以下是各种类型的整数常量的实例:
85 //十进制
0213 //八进制
0x4b //十六进制
30 //整数
30u //无符号整数
30l //长整数
30ul //无符号长整数
浮点常量
浮点常量有整数部分、小数点、小数部分和指数部分组成。可以使用小数形式或者指数形式来表示浮点常量。
当使用小数形式表示时,必须包含整数部分、小数部分,或同时包含两者。当使用指数形式表示时,必须包含小数点、指数,或同时包含两者。带符号的指数使用e或E引入的。
下面列举几个浮点常量的实例:
3.14159 //合法的
314159E-5L //合法的
510E //非法的:不完整的指数
210f //非法的:没有小数或指数
.e55 //非法的:缺少整数或分数
字符常量
字符常量是括在单引号中,例如,‘X’可以存储在char类型的简单变量中。
字符变量可以是一个普通的字符(例如‘X’)、一个转义序列(例如‘\t’),或一个通用的字符(例如‘\u02C0’)或制表符(\t)等。下标列出了一些这样的转义序列码:
转义序列 | 含义 |
---|---|
\\ | \字符 |
\’ | '字符 |
\" | "字符 |
\? | ?字符 |
\a | 警报铃声 |
\b | 退格键 |
\f | 换页符 |
\n | 换行符 |
\r | 回车 |
\t | 水平制表符 |
\v | 垂直制表符 |
\ooo | 一到三位的八进制数 |
\xhh… | 一个或多个数字的十六进制数 |
下面的实例显示了一些转义序列字符:
实例
#include<stdio.h>
int main()
{
printf("Hello\tWorld\n\n");
return 0;
}
当上面的代码被编译和执行时,会产生下列结果:
Hello World
字符串常量
字符串字面值或常量是括在双引号" "中的。一个字符串包含类似于字符常量的字符:普通的字符、转义序列和通用的字符。
可以使用空格做分隔符,把一个很长的字符串常量进行分行。
下面的实例显示了一些字符串常量。下面这三种形式所显示的字符串是相同的。
"hello,dear"
"hello,\
dear"
"hello," "d" "ear"
定义常量
在C中,有两种简单的定义常量的方式:
- 使用#define预处理器。
- 使用const关键字。
#define预处理器
下面是使用#define预处理器定义常量的形式:
#define identifier value
具体请看下面的实例:
实例
#include <stdio.h>
#define LENGTH 10
#define WIDTH 5
#define NEWLINE '\n'
int main()
{
int area;
area = LENGTH * WIDTH;
printf("value of area : %d", area);
printf("%c", NEWLINE);
return 0;
}
上面代码被编译和执行时,他会产生下列结果:
value of area:50
const关键字
可以使用const前缀声明制定类型的常量,如下所示:
const type variable=value;
具体请看下面的实例:
实例
#include <stdio.h>
int main()
{
const int LENGTH = 10;
const int WIDTH = 5;
const char NEWLINE = '\n';
int area;
area = LENGTH * WIDTH;
printf("value of area : %d", area);
printf("%c", NEWLINE);
return 0;
}
当上面的代码被编译和执行时,会产生下列结果:
value of area:50
请注意,把常量定义为大写字母形式,是一个很好的编程实践。
注意:#define是宏定义,他不能定义常量,单宏定义可以实现在字面意义上和其他定义常量相同的功能,本质的区别就在于 #define 不为宏名分配内存,而const也不为常量分配内存,因为const并不是去定义一个常量,而是去改变一个变量的存储类,把该变量所占的内存变为只读。
const定义的是变量不是常量,只是这个变量的值不允许改变是常变量!带有类型。编译运行的时候起作用存在类型检查。
define定义的是不带类型的常数,只进行简单的字符替换。在预编译的时候起作用,不存在类型检查。
1、#define与const两者的区别
(1)编译器处理方式不同
- #define宏是在预处理阶段展开。
- const常量是编译运行阶段使用。
(2)类型和安全检查不同 - #define宏没有类型,不做任何类型检查,仅仅是展开。
- const常量有具体的类型,在编译阶段会执行类型检查。
(3)存储方式不同 - #define宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存。(宏定义不分配内存,变量定义分配内存)
- const常量会在内存中分配(可以是堆中,也可以是栈中)
(4)const可以节省空间,避免不必要的内存分配。例如:
#define NUM 3.14159 //常量宏
const doulbe Num = 3.14159; //此时并未将Pi放入ROM中 ......
double i = Num; //此时为Pi分配内存,以后不再分配!
double I= NUM; //编译期间进行宏替换,分配内存
double j = Num; //没有内存分配
double J = NUM; //再进行宏替换,又一次分配内存!
const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是像#define一样给出的立即数,所以,const定义的常量在程序运行过程中只有一份拷贝(因为是全局的只读变量,存在静态区),而#define定义的常量在内存中有若干个拷贝。
(5)提高了效率。编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。
(6)宏替换只作替换,不做计算,不做表达式求解,宏预编译时就替换了,程序运行时,并不分配内存。
注意:define有边缘效应,例:#define N 2+3,N的值是5。
int a=N/2
在编译是预想a=2.5,实际打印结果是3.5,原因是在预处理阶段,编译器将a=N/2处理成a=2+3/2,这就是define宏的边缘效应,所以我们应该写成 #define N(2+3)
#include <stdio.h>
#define LENGTH 10+10
//正确写法 #define LENGTH (10+10)
#define WIDTH 5
#define NEWLINE '\n'
int main(){
int area;
area = LENGTH * WIDTH;
printf("value of area : %d", area);
printf("%c", NEWLINE);
return 0;
}
以上实例输出结果:
value of area : 60
所以如果我们需要得到正确结果应该将 #define LENGTH 10+10修改为 #define LENGTH (10+10)
补充说明
单引号与双引号的区别:
在 C 语言中,单引号与双引号是有很大区别的。
在 C 语言中没有专门的字符串类型,因此双引号内的字符串会被存储到一个数组中,这个字符串代表指向这个数组起始字符的指针;而单引号中的内容是一个 char 类型,是一个字符,这个字符对应的是 ASCII 表中的序列值。
四种进制说明:
在二进制中只有 0、1 两种情况,你不会看到比 1 大的数字。二进制是逢 2 就进位,所有数字中没可能有 2 或大于 2 的数字。
在八进制中有 0、1、2、3、4、5、6、7这八种情况,你也不会看到比7大的数字。八进制是逢8就进位,所有数字中没可能有8或大于8的数字。
在十进制中有0、1、2、3、4、5、6、7、8、9这十种情况,你更不会看到比9大的数字。十进制是逢10就进位,所有数字中有0~9都有。
在十六进制中有 0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F,其中 A 表示 10;B 表示 11;C 表示 12;D 表示 13;E 表示 14;F 表示 15。十六进制数字中含有 A–F字母,它是 0–9+A–F