if
嵌套出现时,else
属于离它最近的不完整的if
switch
的最后一个case
也加上break
是个好习惯,以避免在后面追加新的case
时忘记添加break
goto
通常不是好事,惟一的例外多是须要从多重循环中直接退出时比较方便,可是这也能够经过把整个循环包装成一个函数,而后在须要退出的时候直接return
来解决%
不能用于浮点数移位⚠️C只规定对于unsigned值使用逻辑移位,对于signed值使用的移位方式则由编译器决定!数组
算数移位:ide
右移时只能一位一位移,符号位为0则补0,为1则补1,以保证与原值同号函数
⚠️C中的赋值符实际上会将左值做为运算结果返回,因此下面这种连续赋值实际上是合法的:测试
int x = 3; int y = x = x + 2; // 合法
可是实际上不管x
是否为int
,x + 2
都会返回一个int
结果并赋值给x
,而若x
实际上是一个char
,这样的赋值就会致使结果的高位被截去,于是获得的x
的值的完整性是没法保障的,进而y
的值也不必定符合指望。lua
⚠️sizeof操做符判断它的操做数的类型长度(sizeof不是函数!!),而并不须要知道它的操做数(也能够是表达式)的实际值指针
// 括号 sizeof(x); sizeof x; // 二者彻底等价,以字节为单位返回变量x的长度 // 数组 sizeof(arr); // 返回数组的字节数(不是数组长度!!) // 表达式 sizeof(a = b + 3); // 判断长度不须要知道表达式的实际值,所以sizeof不会执行接收到的表达式,a也并不会被赋任何值 // 给sizeof一个有反作用的表达式将会获得以下警告: // Expression with side effects has no effect in an unevaluated context
⚠️自增 & 自减code
++和--真是C永恒的话题。。
int a = 10; int b = a++; // 合法:a加一的结果先被做为一个值拷贝后赋值给b,而后a被加一 int c = (++a)++; // 非法:++a实际是a值的拷贝,不是一个左值,所以不可自增自减
逗号操做符分隔多个表达式,表达式们从左到右逐个求值,一整条逗号表达式的值等于最后一个小表达式的值。内存
惟一的用处多是用来简化同时出如今while循环前面和内部的语句(能够用逗号链接起来放进while的条件里,而后把原来的条件做为最后一个表达式)。。由于while每一轮开始前都会执行一遍条件
⚠️隐式类型转换ci
C中的整型算数运算至少都会以缺省整型类型的精度来进行,即使全部操做数都是更小的类型(居然是这样!):get
char a, b, c; a = b + c; // 虽然a, b, c全都是较小的char,b和c也会先被提高为int,而后执行加法获得int结果,再将结果截短赋值给a
可是,若是直接参与运算的值已经达到了不用提高的标准而运算结果将会产生溢出,那么即便左边变量足够接收完整的结果,获得的也是先溢出再被加长的值:
int a, b; long c = a * b; // 就算a和b相乘产生溢出,右边表达式的计算结果也只是溢出后的int,不会由于c够大就提高a和b的长度
对于左右都有表达式的运算符,先计算左边表达式仍是先计算右边表达式是由编译器决定的,所以以下表达式的结果实际没法预测:
a = ++b + --b; // C只规定自增自减运算要优先加法运算执行,可是先求加法的左边(++b)仍是右边(--b)则由编译器决定
有更好的例子以下:
f() + g() - h(); // 同级运算符从左到右执行的规则只约束例子中的加法比减法先执行,而不约束执行加法时必定要先算f()再算g()
甚至编译器也能够先把每个小的表达式求出来再作运算:
f() + f() * f(); // 先无视运算优先级,直接求出3个f()再进行总体运算也是能够的,此时3次f()的调用顺序彻底取决于编译器实现
⚠️标准容许将指向数组元素的指针和指向该数组最后一个元素后面那个位置的指针相比较,但不容许将它和指向数组第一个元素以前的内存位置的指针相比较
这是什么神仙规定。。不过大部分状况下查得不严,仍是能够比较的,只是移植性会稍微降低
可变参数列表
stdarg.h
va_list
va_start
、va_arg
、 va_end
#include <stdarg.h> int sum(int argNum, ...) { // 对未知个数的参数求和 va_list args; va_start(args, argNum); // 使用va_start(可变参数列表 + 最后一个命名参数)将args指向可变参数列表的第一个元素 int result = 0; for (int i = 0; i < argNum; i ++) { result += va_arg[args, int]; // 使用va_arg得到可变参数列表中的下一个参数并为它指定类型 } va_end(args); // 使用va_end结束访问可变参数列表 return 0; }