语句
- 空语句
C语言中最简单的语句就是空语句,本身值包含一个分号,空语句本身不执行任务
- 表达式语句
表达式后面加上分号,就可以构成表达式语句,注意表达式语句不一定要有赋值操作,比如: y + 3, getchar() 当这些语句被执行的时候,表达式被求值,但是它的结果不存在于任何地方,而是被丢弃;因为它们没有使用任何赋值操作符
- 代码块
代码块是位于一对花括号之间可选的声明和语句列表:代码块允许把数据声明在非常靠近它使用的地方
{
declarations
statements
}
- 分支语句
分支语句包含 if else,if elseif,switch case 等结构,对于 if else,if elseif结构,注意 if 括号中的判断条件,对用 if 判断内的表达式求值,零值表示为假,非零值表示为真,C语言中并没有bool 类型的定义,(可以认为 if 语句中判断是 bool 值,只是 C语言中规定零值表示为假,非零值表示为真)
switch case 结构示例:(switch内的 expression 的值必须为整型值)
switch(expression) {
case 'A':
statement1;
break;
case 'B':
statement2;
break;
case 'C':
statement3;
break;
case 'D':
statement4;
break;
......
default:
statement5;
}
每个case语句必须包含一个唯一的值,case 后面可以是常量,字面量和常量表达式,常量表达式指的是在编译期间进行求值的表达式,它不能是任何变量
- 循环语句
循环语句包含三种结构,while 结构,for 结构和 do while 结构
while 结构
- 在 while 循环中使用 break 语句,用于永久终止循环,执行完 break 之后的语句就是循环正常结束应该执行的那条语句
- 在 while 循环中使用 continue 语句,用于永久终止当前那层循环,执行完 continue 语句之后,执行流程会重新测试表达式的值,决定是否继续进行循环
for 结构
for(expression1;expression2;expression3) {
statement;
}
statement 称为循环体, expression1 称为初始化部分,expression2 称为条件部分,expression3 称为调整部分
for 语句和 while 语句的区别在于出现 continue 语句的时候,在 for 语句中,continue 语句跳过了循环体的剩余部分,直接回到了调整部分
但是在 while 语句中,调整部分也是 while 语句的一部分,continue 语句也会将其跳过
for 语句几乎和下面的 while 语句的执行流程一致:
expression1;
while(expression2) {
statement;
expression3;
}
do-while 结构
当循环体至少要执行一次的时候,选择 do_while 语句
操作符
C语言中操作符(运算符)列表如下:
类别 | 说明 |
---|---|
算术操作符 | 加 减 乘 除 取余 |
位运算操作符 | 按位与 按位或 按位异或 按位取反 左移 右移 |
赋值操作符 | += -= *= /= %= &= |= ^= <<= >>= |
关系操作符 | 大于 小于 大于等于 小于等于 等于 不等于 |
逻辑操作符 | 逻辑与 逻辑或 逻辑取反 |
逗号操作符 | , |
条件操作符 | ?: |
下标引用 | [ ] |
函数调用 | ( ) |
结构成员 | -> |
单目操作符 | !++ - & ~ -- + * (类型) sizeof |
移位操作符
移位操作符只是简单把一个值向左或者向右移动,在左移位中,值的最左边几位被丢弃,右边多出来的空位用 0 补齐,右移操作存在一个左移操作不曾面临的问题,从左边移入新位时,可以选择两种方案:
一种是逻辑移位,坐标移入的位用 0 填充,
另一种是算术移位,左边移入的位由原先该值的符号位确定,符号位为 1 则移入 1,符号位为 0 则移入的位均为 0
移位运算的两个操作数必须是整数
void _testshiftOperator() {
// m(0x21) << 2 = 132 HEX:0x84
int8_t m = 0x21;
printf("m(0x21) << 2 = %d HEX:%#x\n", m << 2, m << 2);
// -124 HEX:0xffffff84
m <<= 2;
printf("m(0x21) << 2 = %d HEX:%#x\n", m, m);
// m(0x84) >> 2 = -31 HEX:0xffffffe1
m = 0x84;
printf("m(0x84) >> 2 = %d HEX:%#x\n", m >> 2, m >> 2);
m >>= 2;
printf("m(0x84) >> 2 = %d HEX:%#x\n", m, m);
// m(0x70) >> 2 = 28 HEX:0x1c
m = 0x70;
m >>= 2;
printf("m(0x70) >> 2 = %d HEX:%#x\n", m, m);
}
位操作符
对特定位置1的方法:对 0x01 左移特定的位,再和原来的值做按位或运算,
对特定位置0的方法:对 0x01 左移特定的位,取反后原来的值做按位与运算,
// 位操作符 & | ~ ^
void _testBitOperator() {
uint32_t value = 0;
uint32_t bitIndex = 3;
{
// 为某一位置 1 的方法
value = value | 0x01 << bitIndex;
value |= 0x01 << 2;
value |= 0x01 << 3;
value |= 0x01 << 5;
printf("Set BIT 2 3 5 value = %#x \n", value);
}
{
value = 0xFFFFFFFF;
value &= ~(0x01 << 2);
value &= ~(0x01 << 3);
value &= ~(0x01 << 5);
printf("reset BIT 2 3 5 value = %#x \n", value);
}
}
赋值操作符
注意赋值运算符的运算顺序是从右向左赋值
关系操作符
关系操作符产生的结果都是整型值,而不是 bool 类型的值,如果两端的操作符符合操作符指定的关系,表达式的结果为 1,如果不符合结果为 0
关系操作符的结果是整型值,所以可以赋值给整型变量
// 关系操作符 >= <= == !=
void _testrelationalOperator() {
// 10 > 20 ret value : 0 0
int ret = 10 > 20;
printf("10 > 20 ret value: %d %#x \n", ret, ret );
// 10 < 20 ret value : 1 0x1
ret = 10 < 20;
printf("10 < 20 ret value: %d %#x \n", ret, ret);
}
逻辑操作符
逻辑操作符具有短路操作的性质,所以要关心逻辑操作符操作数的顺序,非零值可以作为逻辑上的真的, 零作为逻辑上的假。
所以 a = -10 或者 a =10 a 作为逻辑表达式求值,可以用逻辑上的 true 表示 ,!a 表示逻辑上的 false(因为 C语言没有 bool 值,所以也可以认为 a 作为逻辑表达式求值,和 a = 1 的含义一致)
void _testlogicalOperator() {
int a = -10;
int b = -20;
if (a && b) {
printf("a=-10 b=-20 is true!! \n");
}
if (!a) {
printf("a is false !! \n");
} else {
printf("a is true !! \n");
}
a = 0;
if (!a) {
printf("a is false !! \n");
} else {
printf("a is true !! \n");
}
}
条件操作符
expression1?expression2:expression3
首先计算 expression1,如果它的值为真(非零值),那么整个表达式就是 expression2 的值,expression3 不会进行求值;
如果 expression1 的值为假(零值),那么整个表达式就是 expression3 的值,expression2 不会进行求值;
// 条件操作符
void _testConditionOperator() {
// 10 ? 1 : 2 ret = 1
int ret = 10 ? 1 : 2;
printf("10 ? 1 : 2 ret = %d \n", ret);
// 10 ? 1 : 2 ret = 1
ret = -10 ? 1 : 2;
printf("-10 ? 1 : 2 ret = %d \n", ret);
// 10 ? 1 : 2 ret = 2
ret = 0 ? 1 : 2;
printf("0 ? 1 : 2 ret = %d \n", ret);
}
逗号操作符
expression1,expression2,expression3,......expressionN,
逗号操作符将两个或者多个表达式分隔开来,这些表达式自左向右逐个进行求值,整个逗号表达式的值就是最后那个表达式的值
void _testOtherOperator() {
// 逗号操作符去最右边的值 从左到右进行求值
// (1, 2, 3, 4) ret = 4
int ret = (1, 2, 3, 4);
printf("(1, 2, 3, 4) ret = %d \n", ret);
// (a, a++, a++, a++, a++) ret = 4 a= 5
int a = 1;
ret = (a, a++, a++, a++, a++);
printf("(a, a++, a++, a++, a++) ret = %d a= %d\n", ret, a);
}
单目操作符
!逻辑取反操作符,对操作数进行逻辑取反,和关系操作符一样,逻辑取反操作符实际产生一个整型结果 0 或者 1
~ 对整型类型的操作数进行按位取反的操作,原先的 1 变成 0,0 变成 1
- 产生操作数的负值
+ 产生操作数的正值
& 产生操作数的地址
* 间接访问操作符,和指针一起使用,表示访问指针所指向的值
sizeof 操作符 用于判断它的操作数的类型长度,以字节为单位
sizeof 操作符的操作数可以是变量类型,也可以是变量名,使用变量类型的好处是,此时 sizeof ()的括号不能省略,sizeof 的操作数是数组名时,返回的是实际数组的长度,
判断表达式的长度不需要对表达式进行求值,所以 sizeof( a = b + 1)并没有向 a 赋值,sizeof的值在编译时就会产生。