声明(二十)
2、maybe_unused属性
maybe_unused属性表示某个名称或者实体可能是有意未被使用。maybe_unused属性说明符具有以下语法格式:
[[maybe_unused]]
其中maybe_unused是标准属性标识符。
如果实现支持ISO/IEC 9899:2024标准,maybe_unused用作__has_c_attribute表达式操作数时,表达式值为202311L,即__has_c_attribute( maybe_unused )值为202311L。
maybe_unused属性用于结构、联合、typedef名、对象、结构成员、联合成员、函数、枚举、枚举器、标签的声明。
[[maybe_unused]] void f1(int); int f2([[maybe_unused]] int); [[maybe_unused]] int i = 0; struct s{ int i; [[maybe_unused]] int bi : 4; double d; };
如果名称或者实体声明时未使用[[maybe_unused]]属性说明符,后续声明可以使用该属性说明符重新声明,反之亦然。实体从首次使用[[maybe_unused]]属性说明符声明开始,后续所有使用均受此属性约束。
对于具有[[maybe_unused]]属性的实体,无论是否使用,ISO标准不建议发出诊断信息。
3、deprecated属性
deprecated属性用于标记那些仍被允许使用、但由于某些原因不推荐使用的名称或者实体。deprecated属性说明符具有以下两种语法格式:
[[deprecated]] [[deprecated( string-literal )]]
其中deprecated是标准属性标识符,string-literal是字符串字面量。
如果实现支持ISO/IEC 9899:2024标准,deprecated用作__has_c_attribute表达式操作数时,表达式值为202311L,即__has_c_attribute( deprecated )值为202311L。
deprecated属性用于结构、联合、typedef名、对象、结构成员、联合成员、函数、枚举、枚举器的声明。
struct [[deprecated]] s{ int i; double d; }; [[deprecated("The function is unsafe.")]] bool f1(struct s *);
如果名称或者实体声明时未使用[[deprecated]]属性说明符,后续声明可以使用该属性说明符重新声明,反之亦然。实体从首次使用[[deprecated]]属性说明符声明开始,后续所有使用均受此属性约束。
当程序引用而不是声明一个具有deprecated属性的名称或者实体时,如果该引用不在相关实体的上下文中,实现应使用deprecated属性生成诊断信息。诊断信息应包含属性实参子句中的字符串字面量文本。
struct [[deprecated]] s{ //不会生成诊断信息。 int i; double d; }; [[deprecated("The function is unsafe.")]] bool f1(int); //不会生成诊断信息。 bool f2(struct s *); //生成诊断信息,引用了struct s类型。 ... struct s s1 = {3, 3.14}; //生成诊断信息,引用了struct s类型。 f1(0); //生成诊断信息,调用了f1函数。
4、fallthrough属性
fallthrough属性用于switch语句,目的是显式告知编译器,当前分支的穿透行为是有意的,而非遗漏break语句,从而避免因控制流穿透产生警告。
switch语句的穿透行为(fallthrough behavior)是指当某个case分支匹配成功后,如果该case分支不存在break语句,程序会执行后续case分支,直至遇到break语句或者switch语句结束。
enum week{Sun, Mon, Tue, Wed, Thu, Fri, Sat}; enum week today; ... switch(today) { case Mon: //存在穿透行为。 case Tue: //存在穿透行为。 case Wed: //存在穿透行为。 case Thu: //存在穿透行为。 case Fri: puts("Today is a weekday."); break; case Sat: //存在穿透行为。 case Sun: puts("Today is the weekend."); break; default: puts("The data is out of range."); break; }
属性标记fallthrough仅出现在属性声明中,此类声明称为fallthrough声明。fallthrough属性说明符具有以下语法格式:
[[fallthrough]]
其中fallthrough是标准属性标识符。
如果实现支持ISO/IEC 9899:2024标准,fallthrough用作__has_c_attribute表达式操作数时,表达式值为202311L,即__has_c_attribute( fallthrough )值为202311L。
fallthrough声明应出现在switch语句中;fallthrough声明后下一个块项目应是与最内层switch语句关联的case标签或者default标签。如果fallthrough声明包含在迭代语句中,下一条语句应是最内层迭代语句次级块(secondary block)的同一执行的一部分;即如果fallthrough声明包含在迭代语句中,其穿透目标必须属于同一轮循环,不能跨循环穿透。
int number = 1; switch(number) { case 1: //其它语句。 [[fallthrough]]; case 2: //其它语句。 [[fallthrough]]; default: //其它语句。 break; } for(int i=0; i<3; i++) { switch(number) { case 1: //其它语句。 [[fallthrough]]; case 2: //其它语句。 [[fallthrough]]; default: //其它语句。 break; } } switch(number) { case 2: //违反约束,下一条语句不是最内层迭代语句次级块的同一执行的一部分。 do{ [[fallthrough]]; } while(false); default: //其它语句。 break; case 1: //其它语句。 [[fallthrough]]; //违反约束,fallthrough声明后无case标签和default标签。 }
使用fallthrough声明的目的是抑制穿透到case标签或者default标签时实现发出的诊断信息;如果fallthrough声明不是动态可达(dynamically reachable),实现应发出诊断信息。
(注:动态可达是指代码在程序运行时可以被执行到。)
switch(number) { case 2: if(number<2) { [[fallthrough]]; //fallthrough声明动态不可达,实现应发出诊断信息。 } default: //其它语句。 break; }
5、noreturn和_Noreturn属性
noreturn属性和_Noreturn属性用于函数,表示函数不会返回给调用者(例如在函数内调用exit函数、abort函数等。)。noreturn属性说明符和_Noreturn属性说明符具有以下语法格式:
[[noreturn]] [[_Noreturn]]
其中noreturn和_Noreturn是标准属性标识符。
当_Noreturn用作属性标记(而非函数说明符)时,其约束和语义与noreturn属性标记完全相同;但从ISO/IEC 9899:2024标准开始,将_Noreturn用作属性标记认为是一种过时做法。
如果实现支持ISO/IEC 9899:2024标准,noreturn用作__has_c_attribute表达式操作数时,表达式值为202311L,即__has_c_attribute( noreturn )值为202311L。
如果函数的任何声明指定了noreturn属性,该函数的第一个声明必须指定noreturn属性。
如果函数在某一编译单元中声明时指定了noreturn属性,而在另一编译单元中声明时未指定noreturn属性,其行为未定义的。
如果函数调用时调用了具有noreturn属性的函数,而该函数最终执行了返回操作(例如:执行了return语句或者执行到函数体末尾。),其行为是未定义的。
//i不等于0时,函数func行为是未定义的。 [[noreturn]] void func(int i) { if(i!=0) puts("i is not equal to 0."); else exit(i); }
具有noreturn属性的函数如果能够返回给调用者,编译时实现应发出诊断信息。此外对于具有noreturn属性、返回类型不是void类型的函数,ISO标准也建议编译时发出诊断信息。
[[noreturn]] int func(int); //建议发出诊断信息。