C语言基本概念之表达式
原文地址:http://blog.csdn.net/astrotycoon/article/details/50857326 【侵删】
什么是表达式(表达式的定义)?
对于表达式的定义,好像从来没有人关注过。今天就孔乙己一把吧,哈哈。先贴标准对expression的定义(ISO/IEC 9899:2011 6.5):
An expression is a sequence of operators and operands that specifies computation of a value, or that designates an object or a function, or that generates side effects, or that performs a combination thereof. The value computations of the operands of an operator are sequenced before the value computation of the result of the operator.
标准就是标准,不搞的晦涩难懂都不好意思拿出来,哈哈。我们来解读一下吧。
“An expression is a sequence of operators and operands that specifies computation of a value”这句明确给了表达式的定义:即表达式是由一系列操作符(operators)和操作数(operands)组成的。这既是表达式的定义,同时也指明了表达式的组成成份。
我们来看几个合法的表达式,如下:
4
-6
4 + 21
a * (b + c/d) / 20
q=5*2
x=++q % 3
q > 3
"hello world"
可以看到一个表达式也可以没有操作符,例如“4”这种形式就是最简单的表达式形式,即最简单的表达式只有一个常量或一个变量名称而没有操作符。
还可以看出,一些表达式是多个较小的表达式的组合,这些小的表达式被称为子表达式(subexpression)。例如表达式c/d是表达式a * (b + c/d) / 20的子表达式。
表达式有什么作用(表达式的目的)?
继续解读标准,可以看到表达式的目的有如下几个:
(1)计算数值(computation of a value)。
哈哈,这个目的其实是表达式的主要目的。
很好理解,例如表达式“3+2”的目的就是计算数值3和2的和。于此同时,表达式同时也表示这个计算所得到的值。具体的可以参阅下面的“表达式属性”小节。
(2)指明数据对象或者函数(designates an object or a function)
例如程序中有int i;声明语句,那么表达式i=3中子表达式i就指代i所代表的那个对象(object),即一块连续的内存空间。
而在表达式&printf中printf指代的是标准C库中的printf函数。
(3)产生副作用(generate side effects)
首先要明白什么是副作用,还是看标准(ISO/IEC 9899:2011 5.1.2.3)
Accessing a volatile object, modifying an object, modifying a file, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment. Evaluation of an expression in general includes both value computations and initiation of side effects. Value computation for an lvalue expression includes determining the identity of the designated object.
OK,副作用(side effects)就是运行时对数据对象或文件的修改。来看几个例子:
①表达式 i = 50的副作用是将变量i的值设置为50,这样说是不是让你感到惊讶呢? 这怎么可能是副作用呢,看起来更像是主要目的啊! 然而,从C的角度来看,主要的目的却是对表达式求值。
②表达式printf("ABC")的值为3(实际打印的字符数,不包括字符'\0'),副作用就是在标准输出设备上连续打印字符A、B和C。
注意,并不是所有的表达式都有副作用,表达式2+3的值为5,但是没有任何副作用。
(4)以上目的的组合(combination)
最后来看一个完整的程序吧:
- #include <stdio.h>
- static int print(void)
- {
- printf("hello world\n"); /* Genearates side effect */
- return (100);
- }
- int main(int argc, const char *argv[])
- {
- int a, b;
- a + b; /* A computation */
- a; /* An object */
- print(); /* A function */
- a = b; /* Genearates side effect */
- a = b, a + print(); /* A combination of all above */
- return (0);
- }
需要注意的是,函数调用也是表达式,print()这个表达式中()是操作符,而print是操作符()的操作数。
表达式的属性有哪些(表达式的属性)?
好了,在阅读了上面两小节之后,想必对什么是表达式以及表达式的诸多作用应该有个清晰的认识了吧。那么,在C语言中一个表达式到底具有哪些属性呢? 首先给出结论如下:
简单说明一下:既然我们知道一个表达式最终会产生一个值,那么任何值在C中肯定是具有类型的。对吧,毋庸置疑啊。
但是,你可能会质疑这样一种情形,在C中如果一个函数的返回值类型为void,例如对函数void aa(int)的调用aa(),这样的表达式也会有值吗? 关于这点我也不是很清楚,在wikipedia中有这样一段:In C and most C-derived languages, a call to a function with a void return type is a valid expression, of type void. Values of type void cannot be used, so the value of such an expression is always thrown away.
所以,记住表达式有两个属性就OK,没必要搞的太咬文嚼字!
--------------------------------------------------------------------------------------------------------------------------------------------
(2016-3-23 16:55:14)补充:其实标准对void表达式是有说明的,如下(ISO/IEC 9899:2011 6.3.2.2):
The (nonexistent) value of a void expression (an expression that has type void) shall not be used in any way, and implicit or explicit conversions (except to void) shall not be applied to such an expression. If an expression of any other type is evaluated as a void expression, its value or designator is discarded. (A void expression is evaluated for its side effects.)
可以看到,void expression的类型是void类型,值为void类型的值, 只是不存在这种值罢了。此外,对void expression的任何显式或者隐式的转换都是不允许的,而将其它类型的表达式的值转化为void类型的值是允许的,编译器会将这个值丢弃(可以说绝大多数情况下,void expression的目的就是产生副作用)。
--------------------------------------------------------------------------------------------------------------------------------------------
我们可以借助gdb提供的print和ptype命令来实际地查看表达式的值和类型两大属性。
- (gdb) ptype 1
- type = int
- (gdb) ptype 1.0
- type = double
- (gdb) ptype "hello world"
- type = char [12]
- (gdb) print printf("hello world\n")
- hello world
- $2 = 12
- (gdb) ptype printf("hello world\n")
- type = int
- (gdb) ptype setbuf(stdout, 0)
- type = void
- (gdb) print setbuf(stdout, 0)
- $3 = void
可以看到在C中字符串常量的类型是字符型数组。setbuf的返回类型为void,我们在使用print打印其值是没有意义的,因此gdb索性给了个void。
有哪些种类的表达式(表达的分类)?
在C中,表达式的种类几乎是与操作符相对应的。可是我们在第一小节也看到了,最简单的表达式形式也可以没有操作符,对于这种没有操作符的表达式在C标准中又分为两类,分别是基本表达式(primary expression)和常量表达式(constant expression)。现在我们把C中的表达式全部列出来,加上简略的说明即可。
- 基本表达式(primary expression)
- 常量表达式(constant expression)
- 后缀表达式(postfix expression)
- 一元表达式(unary expression)
- 强制转换表达式(cast expression)
- 乘法表达式(multiplicative expression)
- 加法表达式(additive expression)
- 移位表达式(shift expression)
- 关系表达式(relational expression)
- 相等表达式(equality expression)
- AND表达式(AND expression)
- 异或表达式(exclusive OR expression)
- 或表达式(inclusive OR expression)
- 逻辑与表达式(logical AND expression)
- 逻辑或表达式(logical OR expression)
- 条件表达式(conditional expression)
- 赋值表达式(assignment expression)
表达式与语句的关系
表达式求值的规则
C语言基本概念之表达式的更多相关文章
- 001_C/C++笔试题_考察C/C++语言基础概念
(一)文章来自:C/C++笔试题-主要考察C/C++语言基础概念.算法及编程,附参考答案 (二)基础概念 2. 头文件中的ifndef/define/endif的作用? 答:防止该头文件被重复引用. ...
- [程序设计语言]-[核心概念]-02:名字、作用域和约束(Bindings)
本系列导航 本系列其他文章目录请戳这里. 1.名字.约束时间(Binding Time) 在本篇博文开始前先介绍两个约定:第一个是“对象”,除非在介绍面向对象语言时,本系列中出现的对象均是指任何可以有 ...
- 0.数据结构(python语言) 基本概念 算法的代价及度量!!!
先看思维导图: *思维导图有点简陋,本着循循渐进的思想,这小节的知识大多只做了解即可. *重点在于算法的代价及度量!!!查找资料务必弄清楚. 零.四个基本概念 问题:一个具体的需求 问题实例:针对问题 ...
- 《C语言程序设计现代方法》第2章 C语言基本概念
C语言的基本概念 第一个C程序例子. /* pun.c */ #include <stdio.h> int main(void) { printf("To C, or not t ...
- C语言基本概念
1. 标准C语言 C语言诞生于20世纪70年代,年龄比我们自己还要大,期间产生了很多标准,但是各种编译器对标准的支持不尽相同. ANSI C是使用的最广泛的一个标准,也是第一个正式标准,被称为“标准C ...
- C语言之运算符、表达式和语句
#include<stdio.h> #define ADJUST 7.31 int main(void) { const double SCALE = 0.333; double shoe ...
- 重学C语言---05运算符、表达式和语句
一.循环简介 实例程序 /*shoes1.c--把一双鞋的尺码变为英寸*/#include <stdio.h>#define ADJUST 7.64#define SCALE 0.325 ...
- C语言中的逗号表达式
转载:http://www.cnblogs.com/hnrainll/archive/2011/08/03/2126660.html C语言提供一种特殊的运算符——逗号运算符.用它将两个表达式连接起来 ...
- 重温C语言(1)----计算算术表达式的值
<C程序设计语言>练习题 5-10 编写程序 expr,计算从命令行输入的逆波兰表达式的值,其中每个运算符或操作数用一个单独的参数表示.例如,命令 expr 2 3 4 + * 计算表达式 ...
随机推荐
- postgresql版sde(10.4.1)安装说明
从ArcGIS 10.3开始,彻底没有了sde的安装包,安装sde数据库需要先安装arcgis desktop,通过arccatalog建数据库,同时也不能建sde服务,只能使用直连 以下演示在sde ...
- Understanding Scroll Views 深入理解 scroll view 读书笔记
Understanding Scroll Views 深入理解 scroll view 读书笔记 It may be hard to believe, but a UIScrollView is ...
- Performance engineering introduction
1.Performance Software performance is one of software quality attributes, it equal to efficiency w ...
- Oracle创建用户及权限设置
oracle用户创建及权限设置 权限: create session create table unlimited tablespace connect resource dba 例: #sqlplu ...
- 使用代码编辑器Sublime Text 3进行前端开发及相关快捷键
推荐理由: Sublime Text:一款具有代码高亮.语法提示.自动完成且反应快速的编辑器软件,不仅具有华丽的界面,还支持插件扩展机制,用她来写代码,绝对是一种享受.相比于浮肿沉重的Eclipse, ...
- Android掌中游斗地主游戏源码完整版
源码大放送-掌中游斗地主(完整版),集合了单机斗地主.网络斗地主.癞子斗地主等,有史以来最有参考价值的源码,虽然运行慢了一点但是功能正常,用的是纯java写的. 项目详细说明:http://andro ...
- centos开机直接进入命令行
找到文件,/etc/inittab 文件,在下面有一行 id:5:initdefault: 将上面的5改成3就可以了 5是图形界面 3是命令行界面 就是文本界面.
- 螺旋数字的python实现
螺旋数字的算法简单实现. 示例 5 01 02 03 04 05 16 17 18 19 06 15 24 25 20 07 14 23 22 21 08 13 12 11 10 09 通过观察,外部 ...
- 一个SAP开发人员的双截棍之路
由于种种原因,Jerry最近加入了SAP成都研究院的一个演讲俱乐部,这个俱乐部主要是提高大家的英语演讲能力. 说来Jerry也是大一下期和大二上期一次性高分通过四六级考试的,但是当毕业进入SAP成都研 ...
- jq打印
1.引入jQuery.print.min.js 2.将需要打印的东西用div包起来 3. $(".printDiv").print();