文章目录

  • 1、表达式的故事
  • 2、表达式的作用
  • 3、表达式的定义
  • 4、题外话

1、表达式的故事

  很清楚记得小白在读大学的时候,当时教C语言的老师在课堂上问的一句话:同学们,什么是表达式?,于是我就去翻书,书里面是这样说的,“由变量、常量和函数调用按C语言语法规则用运算符连接起来的式子称为表达式”,这看似是一个很完整的定义,当时小白也以为自己懂了,但是老师接着问“一个常量数字10是表达式吗?”,当时就懵逼了,如果按照书本讲的,得是这些东西的运算符组合起来才叫表达式,单纯一个数字算什么表达式,结果老师说它是,当时我头上一堆问号;

  然后老师在黑板上写extern void Fun(void); &Fun这个玩意是表达式吗?没错,我头上的问号直接以指数形式增加,&Fun根本不在书本说的范围内,怎么能算表达式呢,老师依然说它是,至此我深深怀疑这本教科书是不是盗版的,为什么这么不严谨,但是最后知道其实书本也只是照搬标准定义,标准定义本身就是一句总结,要扒开内层具体定义这个事情是要自己做的,真的是想说爱你不容易,而老师也是给出他对表达式的闭环定义,其实具体内容我已经忘记了,但是不阻碍我重新学习;

  老师坚定要给出这种闭环定义,其实他的目的在于用机器去进行验证一个东西是不是表达式而不是靠人去判断,写一个程序,给定输入,就能输出结果是否符合表达式定义,如果只用标准定义,那么你想写程序都不知道如何入手,这个时候需要一个清晰的、一步步的、可以用演绎推理得到答案的闭环定义,这种思维是很值得学习的,如果一个东西逻辑清晰有条理,那就想着机器能不能完成这个判断,可以帮助你深入理解一个事情;

2、表达式的作用

  其实在定义之前,要先提及一下表达式的作用,不然定义会让你看着一脸懵,为什么会是这样的定义,它是和作用紧密联系的,表达式的作用是C语言标准里面有明确描述的,很感谢这篇文章它帮我翻译了C语言标准里面的英文:

https://blog.csdn.net/astrotycoon/article/details/50857326

  表达式的作用如下:
1)、计算数值,这是表达式最重要的作用,就是得到一个值,例如表达式3+2的目的就是计算数值3和2的和
2)、指明数据对象或者函数,就是变量名和函数名,例如程序中有int i;声明语句,那么表达式i=3中子表达式i就指代i所代表的那个对象,即一块连续的内存空间。而在表达式printf()printf指代的是标准C库中的printf函数。
3)、产生副作用,就是运行时对数据对象的修改,比如
   ①表达式i = 50的副作用是将变量i的值设置为50
   ②表达式printf("ABC")的值为3(实际打印的字符数,不包括字符'\0'),副作用就是在标准输出设备上连续打印字符A、BC
   注意,并不是所有的表达式都有副作用,表达式2+3的值为5,但是没有任何副作用。
4)、以上1/2/3的组合

3、表达式的定义

  终于到主角登场了,什么是表达式,表达式的定义是什么?
【1】、用于标识某个实体的标识符是表达式(变量名 / 函数名,其中函数名是不可修改的左值)
【2】、常量是表达式(数字/字符/字符串,其中字符串是不可修改的左值,数字和字符不能是左值)
【3】、函数调用是表达式(通过函数名调用 / 通过地址调用)
【4】、带括号的表达式是表达式
【5】、表达式和表达式的合法运算是表达式
【6】、对一个表达式进行合法单目运算的结果是表达式(取址(&)、指针取值(*)、强制类型转换等)

  其中1-2-3都是基准,4-5-6意思是由若干基准的组合结果也属于定义内,这就是闭环定义,可以由这些条目解析一切内容是不是表达式。这个定义是根据表达式的作用反推的,因为表达式都有作用,所以闭环定义中必须让表达式都有作用;

  其实在在正常编程中,我们常见就是a + b 、 a++这些内容,很容易能判断是表达式,因为它直接能套用标准定义,但是像10、&Fun这些的话,标准定义就难以判断了,接下来我们通过例子实际去用一下闭环定义,看看效果如何:

void Fun(void){/** 符合闭环定义的【2】,是表达式,作用是计算数值,得到10*/10; }
void Fun(void){/** 首先整个玩意都不属于【1】~【4】和【6】,因此需要验证是否符合【5】,+是一个加号运算,两边都是常量属于合法运算 * 而常量符合【2】,所以符合【5】,是表达式,作用是计算数值,得到8* */3+5;}
void Fun(void){/** 首先-1是一个常量符合【2】,(-1)符合【4】,强制类型转换符合【6】,是表达式,作用是计算数值,得到255 * */(uint8_t)(-1); }
void Fun(void){/** 首先-1是一个常量符合【2】,(-1)符合【4】,++属于单目运算要去找【6】,但是常量是不能作为左值被改变,因此不合法,不是表达式 * */-1++;}

  由上面的推理例子,你能继续推理下面的内容吗?要描述闭环定义和作用;

extern void Fun(void);void Test(void){&Fun;Fun++;(Fun);Fun;Fun();}
void Fun(void){123;&123;123++;(&"123")();&"123"();}
void Fun(void){uint8_t i = 0;i;i++;i+++1;-1i;-i1;}

4、题外话

  这次的话题会比较枯燥生僻,其实是否知道什么是表达式,能不能讲出定义,这个事情本身不是很重要,就算你不知道不了解,也不影响你工作和学习中的正常编程,只是说如果你真的热爱C语言,你就应该知道一些别人不知道或者不想知道的事情,才能彰显你的热爱程度,就像有2个人都说是周杰伦的铁粉,A说他会唱稻香、双截棍、七里香……,B说周杰伦是x年在y地出道,个人发布的第1个歌曲是z,他大学有m糗事,现在家里n台车,冷门的音乐有p……,就这样子,你觉得A真的是铁粉吗?真的狂热吗?真的热爱吗?还是只是普通的听听歌而已呢?其实家里有几台车这些事情正常人是不会去关心的,但是狂热者就是要去知道他的所有。