注:本课程参考文献《C安全编码标准》
欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~
目录
一.不要通过连接创建通用字符名称
1.1背景
C语言标准支持使用通用字符名称来表示那些不在基本字符集中的字符。这些通用字符名称可以用在标识符、字符常量和字符串常量中。具体来说,\Unnnnnnnn形式的通用字符名称表示一个8位数字短标识符为nnnnnnnn的字符,而\unnnn形式的通用字符名称则表示一个4位短标识符为nnnn(相当于8位短标识符为0000nnnn)的字符。
1.2注意
如果字符序列是通过符号连接来匹配通用字符名称,那么会产生未定义的行为。通常,除非确实有必要,否则在标识符中应当避免使用通用字符名称。
1.3案例
#define assign(uc1,uc2,val) uc1##uc2 = val
void func(void) {
int \u0401;
assign(\u04,01,4);
}
#define assign(uc1,uc2,val) uc1##uc2 = val
- 这行代码定义了一个宏
assign
,它接受三个参数:uc1
、uc2
和val
。 uc1##uc2
是一个宏的连接操作(token pasting operator),它将uc1
和uc2
两个参数连接成一个新的标识符。= val
是将连接后的标识符赋值为val
。
void func(void) {
- 定义了一个名为
func
的函数,该函数没有参数,返回类型为void
。
int \u0401;
- 这行代码声明了一个整型变量,但其名称使用了Unicode字符表示法
\u0401
。在C语言中,\u
后面跟随的四个十六进制数字表示一个Unicode字符。\u0401
代表的是西里尔字母"Ё"的大写形式。
assign(\u04,01,4);
- 这行代码使用了之前定义的
assign
宏来为变量赋值。 \u04
和01
作为assign
宏的参数,通过宏的连接操作,它们被连接成一个新的标识符,即\u0401
,也就是之前声明的变量名。4
作为第三个参数,表示要将变量\u0401
的值设置为4
。
这部分代码通过符号连接生成通用字符名称。
1.4安全修改方案
#define assign(ucn,val) ucn=val;
void func(void){
int \u0401;
assign(\u0401,4);
}
1.5小练习
请你让这部分代码变得更加安全:
#define CONCAT_AND_ASSIGN(uc1, uc2, val) uc1##uc2 = val
void anotherFunction(void) {
int \u0041; // 'A' in Unicode
CONCAT_AND_ASSIGN(\u00, 41, 10);
}
1.6答案
在这个案例中,CONCAT_AND_ASSIGN
宏同样使用了 token pasting operator (##
) 来连接两个参数 uc1
和 uc2
,并尝试将结果赋值为 val
。然而,这里 \u00
和 41
被用作参数,意图通过连接它们来形成 \u0041
,即 ASCII 字符 'A'。
修改方案:
#define ASSIGN(var, val) var = val
void anotherFunction(void) {
int \u0041; // 'A' in Unicode
ASSIGN(\u0041, 10);
}
非常感谢您花时间阅读我的博客,希望这些分享能为您带来启发和帮助。期待您的反馈与交流,让我们共同成长,再次感谢!
👇热门内容👇
Orbslam3&Vinsfusion_安城安的博客-CSDN博客
👇个人网站👇