C语言计数法与值后缀实践:从基础到高级的完整指南
对在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*161241可以看到不同进制的格式说明如下。这里有一个易错点那就是以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输出。