从零开始学习嵌入式P3----C语言表达式、字符的输入输出
2026/7/23 4:19:51 网站建设 项目流程

从零开始学习嵌入式P3----C语言表达式、字符的输入输出

书接上文,今天从变量的定义和初始化开始,学习表达式、类型转换、常用运算符及运算符优先级,最后介绍单个字符的输入输出函数getcharputchar。默认在 Linux + GCC 环境下运行。

本篇目标

学完这一篇,我们应该能够:

  • 按规则定义、初始化和修改变量;
  • 理解表达式的值与类型;
  • 区分隐式类型转换和显式类型转换;
  • 正确使用算术、赋值、逗号及sizeof运算符;
  • 看懂运算符优先级并主动使用括号消除歧义;
  • 使用getcharputchar完成单个字符的输入与输出。

一、变量的定义与使用

变量是在程序运行期间值可以改变的数据对象。变量在内存中拥有对应的存储空间,我们通过变量名访问这块空间,并按照变量声明的类型解释其中的数据。

1. 先定义,再使用

变量定义的基本格式如下:

数据类型 变量名;

例如:

shortnum;unsignedshortnum;intcount;unsignedintid;longtotal;unsignedlongaddress;floattemperature;doublevoltage;charcommand;unsignedcharregister_value;

应为布尔不是C语言自带的关键字,使用bool时需要使用<stdbool.h>库调用

#include<stdbool.h>bool really;

2. 变量名的规则

C 语言标识符只能由字母、数字和下划线组成,并且不能以数字开头。

inta1_;// 合法int_a1;// 合法,但不建议int1a;// 错误:不能以数字开头intreturn;// 错误:不能与 C 语言关键字重名

虽然某些库函数名在特定作用域中可能可以被重新声明或遮蔽,但这样做会让代码难以理解,也可能引发编译问题,因此不要把变量命名为printfgetchar等库函数名。

变量名最好做到见名知意。常见命名风格包括:

intMaxScore;// 驼峰命名intint8_t;// 下划线命名,在跨平台开发中很常见

不论选什么,保持一致和能看懂最重要。

3. 初始化和赋值

定义变量时为它设置初始值,称为初始化:

intcount=0;floattemperature=25.0f;charcommand='A';

而变量定义完成后,再使用赋值运算符=修改它的值,则称为赋值:

intcount;floattemperature;charcommand;//定义变量count=0;temperature=25.0f;command='A';

这两种写法看起来相似,但发生的时机不同:

inta=10;// 定义并初始化a=20;// 给已经存在的变量赋值

二、什么是表达式

表达式是由运算符连接常量、变量或其他表达式后形成的式子。例如:

10+20a*b count=count+1

一个表达式通常同时具有两个重要属性:

  • 类型:决定结果按哪种数据类型解释;
  • :执行表达式后得到的结果。

由于C语言中具有多种数据存储类型,表达式中容易出现多种类型的数据。这会改变式子的输出结果。

例如:

10/4// 输出类型是 int,值是 210.0/4// 输出类型是 double,值是 2.5

同样是除法,因为参与运算的数据类型不同,结果也不同。这也是 C 语言初学阶段非常容易出错的地方。


三、混合类型运算与类型转换

当运算符两侧的数据类型不一致时,编译器通常需要先把它们转换为适合共同运算的类型。

1. 常见的隐式转换

当表达式中出现像上文中的不同数据类型经行计算的情况:

2.5/2;

C语言就会默认采用隐形转换机制经行转换。

隐式类型转换由编译器自动完成,常见情况包括:

  • charshort参与整数运算时,通常先将他们转换为int
  • 当运算两侧出现浮点类型时,整数会转换为对应的浮点类型;
  • floatdouble混合运算时,float会转换为double
  • 同等级的有符号和无符号整数混合运算时,转换为无符号类型;

实际的整数转换还会受到类型等级和目标平台表示范围的影响,尤其是有符号数和无符号数混合时,要格外谨慎数据格式。

2. 显式类型转换

有时也会人为经行数据类型的转换。

程序员主动写出的类型转换也称强制类型转换,基本格式为:

(目标类型)表达式

例如:

intcount=10;doubleresult=(double)count/4;

这里先把count转换成double,再参与除法,所以结果为2.5

类型转换只影响表达式求值时采用的类型,不会自动改变原变量的声明类型:

doublevalue=5.27;intint_part=(int)value;// integer_part 为 5,但value 仍然是 5.27

四、不同数据类型的赋值

看图片中的核心代码:

#include<stdio.h>intmain(void){doubled=0;d=10/4;printf("d = %f\n",d);return0;}

很多人会认为d的输出结果是double类型,值为2.5。实际输出却是:

d = 2.000000

原因在于,赋值之前会先计算等号右侧的表达式。104都是int类型,因此执行的是整数除法,小数部分直接被舍弃,先得到整数2,之后这个2才被转换为double并赋给d

10 / 4 -> 整数除法得到 2 -> 转换为 double -> 2.000000

如果想输出double结果,只要让除法中的任意一个操作数在运算前变成浮点类型即可:

d=10.0/4;d=10/4.0;d=(double)10/4;

这三种写法的结果都是2.5


五、算术运算符

C 语言常见的算术运算符如下:

运算符含义示例
+加法a + b
-减法a - b
*乘法a * b
/除法a / b
%取余a % b
++自增a++++a
--自减a----a

1. 除法与取余

两个整数相除时仍然得到整数,会直接省略小数点后面的部分:

inta=10/4;// 2intb=-10/4;// -2

%用来计算整数除法的余数,不能对浮点数使用:

inta=10%4;// 2

2. 前置与后置自增

++--可以粗略理解为:

a++;//a = a + 1a--;//a = a - 1

++--只能作用于可修改的变量,不能作用于常量。且a ++与++ a与不同的含义。

inti=5;inta=i++;// 先使用 i 的旧值完成当前表达式,再令 i 加 1:a = 5,i = 6intj=5;intb=++j;// 先令 j 加 1,再使用新值完成表达式:j = 6,b = 6

如果只是单独写一条自增语句,i++++i都会让i增加 1:

i++;++j;

六、赋值运算符

常用赋值运算符包括:

= -= //a -= 1意为:a=a-1 *= //a *= 1意为:a=a*1 /= //a /= 1意为:a=a/1 %= //a %= 1意为:a=a%1

复合赋值可以让代码更紧凑。

1. 左值与右值

简单理解:

  • 左值表示一个可以被定位的对象,可修改变量能够放在赋值号左边;
  • 右值用于提供参与计算或赋值的值,变量、常量和表达式都可以出现在右侧。
inta=0;intb=10;a=100;// 正确a=b;// 正确a=b+100;// 正确// 100 = a; // 错误:常量不能作为赋值目标// a + b = 0; // 错误:表达式不能作为赋值目标

2. 混合类型赋值

不同类型之间赋值时可能发生转换:

  • 整数赋给浮点变量:整数转换为浮点类型;
  • 浮点数赋给整数变量:小数部分被舍弃;
  • 小范围整数赋给大范围整数:通常进行符号扩展或补 0;
  • 大范围整数赋给小范围整数:可能丢失高位数据;
  • 有符号与无符号整数互相赋值:按目标类型规则转换,结果可能与直觉不同。

例如:

inta=3.99;// a 得到 3doubleb=10;// b 得到 10.0unsignedcharc=355;// 可能得到 99

在常见 8 位unsigned char平台中,355 超出 0-255 的范围,转换结果相当于对 256 取模,因此得到 99。对于不能由目标类型表示的有符号整数转换,具体结果可能由编译器实现决定。


七、符号位

代码:

#include<stdio.h>intmain(void){unsignedinta=5;if(a-10>0){printf("Yes\n");}else{printf("No\n");}return0;}

从数学上看,5 - 10等于-5,条件应该为假。但这段程序通常会输出:

Yes

原因是aunsigned int。表达式a - 10求值时,整数常量10会转换为unsigned int,整个减法执行无符号运算。

无符号整数不能表示负数。当结果越过 0 时,会按照模 2ⁿ 的规则回绕。假设unsigned int为 32 位:

5U - 10U = 4294967291U

这个值当然大于 0,所以程序进入if分支。

如果本来就需要表示负数,则应从一开始选择有符号类型:

inta=5;if(a-10>0){printf("Yes\n");}else{printf("No\n");}

这个例子说明,类型不仅决定变量能保存什么,也会直接改变表达式的计算方式。


八、逗号运算符与sizeof

1. 逗号运算符

逗号表达式从左到右依次计算各个子表达式,并把最后一个子表达式的值作为整体结果:

inta=1;intb=2;intresult=(a+10,b+20);//以最后一个式子为整个表达式的结果// result 的值为 22

逗号运算符的优先级很低,所以通常需要加括号。日常代码不宜用逗号表达式,会降低可读性。

2.sizeof运算符

sizeof用来获取类型或对象占用的存储空间,结果以字节为单位:

#include<stdio.h>intmain(void){inta=0;printf("sizeof(int) = %zu\n",sizeof(int));printf("sizeof(a) = %zu\n",sizeof(a));return0;}

对类型使用sizeof时必须加括号;对变量或普通表达式使用时括号可以省略,但为了统一和易读,通常保留。

sizeof(int);// 正确sizeofa;// 正确sizeof(a);// 正确

九、运算符优先级

当一个表达式中出现多个运算符时,C 语言会按照优先级和结合性决定求值结构。常见运算符从高到低的大致顺序:

优先级类别常见运算符
括号和后缀()、后置++、后置--
单目前置++、前置--!~sizeof、强制类型转换
乘除取余*/%
加减+-
移位<<>>
关系与相等<<=>>===!=
按位运算&^、`
逻辑运算&&、`
条件运算?:
赋值=+=-=*=/=%=
逗号,

不建议仅靠背诵优先级来编写复杂表达式。存在歧义时主动使用括号,既能确保计算顺序,也能让读者快速看懂意图:

intresult=(a+b)*c;

十、常用输入输出函数概览

C 语言的标准输入输出函数声明在<stdio.h>中:

#include<stdio.h>

按处理对象可以粗略分为:

类别常见函数用途
单个字符输入输出getcharputchar一次读取或输出一个字符
格式化输入输出scanfprintf按指定格式处理数据
字符串输入输出fgetsputs读取或输出字符串

十一、putchar输出字符

putchar的作用是在标准输出中写出一个字符,基本用法为:

putchar(字符或字符编码表达式);

例如:

#include<stdio.h>intmain(void){putchar('A');putchar('\n');return0;}

putchar每次只输出一个字符。调用成功时,它返回所输出字符对应的无符号字符值并以int类型表示;失败时返回EOF

虽然putchar一次只能输出一个字符,但可以连续调用来输出一段文字:

#include<stdio.h>intmain(void){putchar('h');putchar('e');putchar('l');putchar('l');putchar('o');putchar('\n');return0;}

也可以利用字符数组和循环实现,不过数组与循环将在后续内容中进一步学习。


十二、getchar输入字符

getchar从标准输入读取一个字符:

intch=getchar();

要注意,它的返回类型是int,而不是char

在普通终端中,标准输入通常按行缓冲。用户输入字符后,往往还需要按下回车,程序才能读取到这一行数据。

小写字母转换为大写字母

利用 ASCII 中大小写字母编码之间的固定差值,可以把输入的小写字母转为大写:

#include<stdio.h>intmain(void){intch=getchar();putchar(ch);putchar('\n');return0;}

小结

这一篇学习了变量的定义、初始化与赋值,理解了表达式具有类型和值,并重点分析了整数除法、显式类型转换以及有符号与无符号混合运算。随后认识了算术、赋值、逗号和sizeof运算符,最后使用getcharputchar完成了单个字符的输入与输出。

嵌入式程序经常直接处理寄存器、计数值和原始字节,类型选择或转换顺序稍有不同,表达式的结果就可能完全改变。看到一条表达式时,不仅要计算它的数学结果,还要先确认每个操作数是什么类型。

因为篇幅原因,本篇内容只讲到字符的输入输出,其他输入输出只能留到下一篇讲。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询