对在C语言中,主要关注的都是字符、整型、浮点型这些数据类型,对于赋值语句的另一个知识点,进制计数法的关注度并不高;作为开发者也许了解过,其中十进制和十六进制在嵌入式中应用还算广泛,不过二进制和八进制就不足了,因此这里统一整理下,进行说明。
进制计数法格式进制计数法格式说明
对于C语言程序,支持使用"前缀+数字"的格式声明进制,支持的进制包含二进制、八进制、十进制和十六进制,具体格式如下所示。
// 二进制, 以0b开头的对象 0b // 八进制 0 // 十进制 // 十六进制 0x // 举例说明 int a1 = 0b1001; // 对应数字9 int a2 = 011; // 对应数字9 int a3 = 9; int a4 = 0xF; // 对应数字15 int a5 = 0xF1; // 对应数字15*16+1=241可以看到,不同进制的格式说明如下。
这里有一个易错点,那就是以0开头的声明的数字,虽然全是由数字组成,却是八进制,如果理解为十进制,其数据就可能不对了,例如下面这段代码。
#include int main(int argc, char *argv[]) { int a1 = 7; int a2 = 07; int a3 = 17; int a4 = 017; printf("a1 = %d\n", a1); // a1 = 7 printf("a2 = %d\n", a2); // a2 = 7 printf("a3 = %d\n", a3); // a3 = 17 printf("a4 = %d\n", a4); // a4 = 15 return 0; }对于上述代码,具体执行结果如下所示。
可以看到,没有进位时,添加0输出还是一致的,但是有进位后添加0会导致值就不同了,八进制的进位和十进制是不一致的。不过八进制在C语言中开发使用频率很低,因此注意声明数字时,除了0以外,其它时候不要以0开头即可;有特殊场景需求时自然会去关注,反而风险比较低。
进制计数法运用
进制计数法不影响数据的存储机制和输出,那么好处主要在于显示更清晰,在某些特殊场景,二和十六进制显示比十进制更清晰,方便用户去分析。对于这些不同进制,主要用于地址定义、赋值和打印显示,这里展示常用的场景。
地址定义和赋值
使用进制计数法可以方便查看,具体示例如下所示。
// flash起始动作 #define FLASH_ADDRESS 0x08000000 // #define FLASH_ADDRESS 134217728 // SDRAM起始地址 #define SDRAM_ADDRESS 0xC0000000 // 赋值寄存器数据 TIM->CR = 0x03000001; // 位操作 int b = 0b0101; b = ~b;可以看到,对于FLASH_ADDRESS来说,两种定义从结果是一致的,但是使用十六进制,可以一眼看出具体的地址,降低了书写出问题的概率,下面写法,多少了几百、几千也发现不了;赋值和位操作也类似,这种写法可以一眼看出结果,降低手写出问题的概率。
打印显示
对于printf格式化,支持对于数值按照不同的格式打印,包含%d、%o、%x和%X,支持不同进制的输出。
具体示例如下所示。
#include int main(int argc, char* argv[]) { int a1 = 42; printf("a1 = %d\n", a1); // a1 = 42 printf("a1 = 0%o\n", a1); // a1 = 052 printf("a1 = 0x%x\n", a1); // a1 = 0x2a printf("a1 = 0x%X\n", a1); // a1 = 0x2A return 0; }对于上述代码,具体执行结果如下所示。
可以看到,可以指定同一个数值在不同进制下输出显示,不过不同进制的前缀需要自己补足。
数字后缀字符
在C语言中,还支持在数字后添加后缀字符,用于表示不同的后缀,具体后缀字符如下所示。
后缀字符
含义
u/U
无符号整数(unsigned)
l/L
在整数后表示长整数(long), 在浮点数后表示长双精度浮点数(long double)
ll
长长整数(long long)
f/F
单精度浮点数(f)
ul/UL
无符号长整数(unsigned long)
这里还有个知识点,如果在声明数字时,没有添加后缀字符,默认会根据数字的范围和精度,自动选择合适的后缀字符;另外还有个比较特别的知识点,就是对于浮点数,如果没有添加后缀字符,默认会被认为是双精度浮点数(double),此时赋值给单精度浮点数(float)时,可能会丢失精度。
对于数字后缀,具体示例如下所示。
#include int main(int argc, char* argv[]) { int a1 = 42; unsigned int a2 = 231u; float f1 = 3.14f; double d1 = 3.1415926; long double d2 = 32424.55; printf("a1 = %d\n", a1); printf("a2 = %u\n", a2); printf("f1 = %f\n", f1); printf("d1 = %lf\n", d1); printf("d2 = %Lf\n", d2); return 0; }对于上述代码,具体执行结果如下所示。
这里还有个格式化的知识点,单精度浮点数使用%f输出,双精度浮点数使用%lf输出,长双精度浮点数使用%Lf输出。