好吧,C23 为语言添加了函数属性,但我不确定是否有人真正考虑过它们应该如何使用。考虑这个例子:
[[deprecated]] int foo () { return 0; }
[[nodiscard]] int bar () { return 0; }
int main()
{
typedef int foo_t ();
foo_t* fp1;
foo_t* fp2;
foo_t* fp3;
fp1 = foo;
fp2 = fp1;
fp3 = bar;
fp1();
fp2();
fp3();
}
这里需要注意的一些事项:
typedef
中指定属性,因为显然属性没有附加到类型。fp1 = foo;
分配期间。 foo
已弃用。fp1
或 fp2
调用已弃用的函数时,我没有收到警告。fp3
时没有收到警告,但忽略/丢弃结果。此外,函数声明和定义之间似乎没有检查。这可以干净地编译:
[[unsequenced]] int foo ();
[[nodiscard]] int foo ();
[[deprecated]] int foo () { return 0; }
为什么我希望编译器允许这样的废话?
函数属性不附加到类型上,那么我们如何才能获得“函数属性正确性”并使其按预期工作呢?或者它们只是简单地未指定/损坏,随心所欲地添加到语言中,以便稍后当有人愿意真正检查它们的后果时修复?
我在这里遗漏了什么吗?
deprecated
的正常用途是某些软件(例如图书馆)的发行商通知客户某些项目已被弃用。为此,他们会在发布的标头中标记函数的声明,而不是函数的定义。当客户端翻译单元使用标记为 deprecated
的项目时,编译器将生成诊断信息。
这足以向客户告知问题。当从该项目复制该项目的值(或有效值,当功能指示符自动转换为地址时)以后进一步使用时,不会产生进一步的诊断,这一事实不会否定初始诊断。此属性无意修改类型和更改有关类型及其在赋值等中的角色的语义。其目的是在客户端使用已弃用的项目时提供诊断,并且它实现了这一点。
使用
nodiscard
,不幸的是属性不能传播到值的副本,但缺点是情况和/或C历史所迫;这不是由于属性设计错误造成的。一些程序将函数地址存储在公共数组中,或者动态地将动态选择的函数地址分配给公共指针。数组元素或公共指针具有单一类型,因此我们不能指定 nodiscard
函数与非 nodiscard
函数是不同的类型。在某些代码结构中,编译器分析可能能够跟踪分配给指针的值,并能够在已知 p();
保存 p
函数的地址时警告 nodiscard
丢弃返回值,但这一般情况下当然不可能。完全跟踪nodiscard
需要执行时支持。