当前位置: C语言 -- 基础 -- 声明

声明(二十)

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); //建议发出诊断信息。