当前位置: C语言 -- 基础 -- 语句和块

语句和块(一)

一、概述

语句(statement)用于指定要执行的操作。C语言中语句可分为标签语句(labeled-statement)和无标签语句(unlabeled-statement)。

无标签语句存在以下三种语法格式:

expression-statement
attribute-specifier-sequenceopt primary-block
attribute-specifier-sequenceopt jump-statement

其中expression-statement是表达式语句,例如:x = 5;attribute-specifier-sequence是属性说明符序列;primary-block是主块,主块可以是复合语句(compound-statement)、选择语句(selection-statement)、迭代语句(iteration-statement);jump-statement是跳转语句,例如:break;


除非另有明确说明,否则语句是按顺序执行的。可选的属性说明符序列属于对应语句,例如:[[fallthrough]];fallthrough属性属于空语句。


块可以是主块、次块(secondary-block),也可以是与函数定义相关联的块;它允许将一组声明或者语句分组为一个语法单元。

int func(void)	//与函数func定义相关联的块开始处。
{ 
  return 0;
} //与函数func定义相关联的块结束处。
...
//整个if语句是一个主块。
if(i>0)
{ //第一个次块开始处。
  return i;
} //第一个次块结束处。
else
{ //第二个次块开始处。
  return -i;
} //第二个次块结束处。

块可以理解为使用{ }符号包含的一组代码,并且有些情况下{ }符号是可以省略的。如果是独立的代码单元,则是主块;如果嵌套在别的块中,则是次块。


如果块B是块A定义的一部分,与块B关联的标识符的作用域和对象的生命周期不会扩展到块B外的块A部分。

{
  {
    int i = 5;
  }

  printf("%d\n", i);
}

编译时会给出类似error: i undeclared(first use in this fucntion)的报错信息。


具有自动存储期限对象的初始化器,以及在具有块作用域的普通标识符声明中出现的任何大小表达式和typeof类运算符,每次按照执行顺序到达声明时,都会被评估并将值存储到对象中(没有初始化器的对象表示是不确定的。),就像它是一个语句,并在每个声明中按声明符出现的顺序处理。

{
    int a = 3;			//a的值为3。
    int b = a + 5;		//b的值为8。
    int a1[a+b];		//数组a1包含11个数组元素。
    typeof(int [a+2]) a2;	//数组a2包含5个数组元素。
    int i;			//i的值是不确定的。
}

完整表达式(full expression)是不属于其它表达式,也不是声明符或者抽象声明符一部分的表达式。以下各项都是完整表达式:

-- 可变修改类型的完整声明符。

int n = 5;

//(*ptr)[n]是完整声明符,也是完整表达式。
int (*ptr)[n];

-- 不属于复合字面量的初始化器。

struct s{
    int i;
    double d;
};

struct s s1 = {1, 1.23};    //1和1.23都是完整表达式。
struct s s2 = (struct s){3, 3.14};  //3和3.14不是完整表达式,它们都是复合字面量的一部分。

-- 表达式语句中的表达式。

表达式语句可理解为表达式后面跟;符号构成,整个表达式是完整表达式。

i = 3;  //i = 3是完整表达式。
i++;    //i++是完整表达式。

-- 选择语句(if或者switch)的控制表达式。

if(i>0) //i>0是完整表达式。

-- while或者do语句的控制表达式。

while(i != 0) //i != 0是完整表达式。

-- for语句中的每个(可选的)表达式。

for(i=0; i<5; i++)  //i=0、i<5、i++都是完整表达式。

-- return语句中的(可选的)表达式。

return (a+b);   //(a+b)是完整表达式。

对于隐式完整表达式(implicit full expression),会对可变修改类型的非常量大小表达式进行评估;同一完整表达式内不同大小表达式的评估顺序是无序的。

:隐式完整表达式是编译器插入的表达式,这类表达式的作用通常是进行资源清理或者对象销毁。)

int i = 10;
int arr[i+1][i++];

数组arr可能是arr[12][10],也可能是arr[11][11],这与子表达式i+1i++的评估顺序有关。


完整表达式的评估与下一个完整表达式的评估之间存在一个序列点(sequence point)。

虽然常量表达式满足完整表达式的定义,但常量表达式的评估既不依赖任何副作用,也不会产生任何副作用,因此作为完整表达式的执行顺序意义对于常量表达式来说是没有意义的。