- C安全编码标准 笔记(1)
-
2011-11-22 23:11:28
-
1) 用内联函数或静态函数代替与函数相似的宏
-
因为宏是危险的,不小心就会传入一个带副作用的参数,比如i++. 这会引起未定义的行为。
-
因为语句替换,错误的绑定同名的局部变量和全局变量。
-
宏的交错执行在同一表达式中组合在一起,因为参数操作的顺序可能导致未定义的行为。
-
-
例外:
-
用于实现局部函数的的宏无法用内联函数实现,即闭包的功能之一。
-
宏可以支持某种形式的惰性计算,内联函数无法实现该功能 例如 #define select(s,v1,v2)((s)?(v1):(v2)),根据选择结果,只计算v1,v2中的一个值。
-
宏可以用于产生编译时常量。
-
宏可以用于实现类型通用的函数,C++借助模板这样的机制实现。
-
宏参数具有按名称调用的语义,而函数则是按值调用。
-
-
2)在宏参数名两边加上括号
-
保证语句正确展开,这个比较常见。
-
-
例外:
-
当替换文本中的参数名由逗号分隔时,不管实际参数如何复制,因为逗号优先级低于其他任何操作符,不会导致意外替换。
-
使用##操作符连接变量,使用#把宏参数转换为一个新的标记。或者相邻的字符串常量,不能对宏参数加上括号。
-
-
3)宏替换列表应该加上括号
-
用以保护表达式中所有优先级较低的函数
-
防止错误展开,导致出乎本意的行为
-
-
例外:
-
如果一个宏展开为单个标识符或者函数调用,行为可控,不需要括号保护。
-
-
4)应该用typedef定义编码类型
-
typedef定义遵循作用域规则,且能正确定义指针类型,宏展开不遵循且不能正确体现指针定义。
-
-
5)不要复用标准头文件名
-
行为未定义.
-
-
6)理解链接标记或者执行字符串化时的宏替换
-
预处理符##用于把两个标识符合并为一个标记符
-
当宏参数前面有个#是,预处理器就会用实际参数的文本来替代它,并转化为一个字符串常量
-
要注意宏展开的时机。什么时候发生的替换
-
-
7)把头文件放在包含防护文件中
-
避免同一个同文件重复包含,导致变量定义重复。
-
-
8)避免使用连续的问号
-
??= #
-
??( [
-
??) ]
-
??/ \
-
??< {
-
??> }
-
??' ^
-
??! |
-
??- ~
-
当出现左面的三字符的时候,会被替换为右面的字符。为避免意外,慎用三字符。
-
-
9)保证头文件名唯一
-
-
10)不用非安全函数代替安全函数
-
以防潜在缓冲区溢出
-
-
11)在一个 do-while 循环中包装多条语句的宏
- 在内核文件中常见。用于把多条语句序列作为一个块执行。降低编译出错概率。