美文网首页
编译阶段能做什么:属性和静态断言

编译阶段能做什么:属性和静态断言

作者: Drew_MyINTYRE | 来源:发表于2021-06-20 10:54 被阅读0次

“编译阶段”的目标是生成计算机可识别的机器码。

编译是预处理之后的阶段,它的输入是(经过预处理的)C++ 源码,输出是二进制可执行文件(也可能是汇编文件、动态库或者静态库)。这个处理动作就是由编译器来执行的。

有没有用来控制编译器的“编译指令”呢?如果有这么一个东西,让程序员来手动指示编译器这里该如何做、那里该如何做,就有可能会生成更高效的代码。

到了 C++11,标准委员会终于认识到了“编译指令”的好处,于是就把“民间”用法升级为“官方版本”,起了个正式的名字叫“属性”。你可以把它理解为给变量、函数、类等“贴”上一个编译阶段的“标签”,方便编译器识别处理。
“属性”没有新增关键字,而是用两对方括号的形式“[[…]]”,方括号的中间就是属性标签,注意属性的编写规范,作用范围。

[[noreturn]]              // 属性标签
int func(bool flag)       // 函数绝不会返回任何值
{
    throw std::runtime_error("XXX");
}

 //  声明变量暂不使用,不是错误
[[gnu::unused]]     
int nouse;  

 // C++14 or later
// 当然,程序还是能够正常编译的,但这种强制的警告形式会“提醒”用户旧接口已经被废弃了,应该尽快迁移到新接口。
[[deprecated("deadline:2020-12-31")]]     
int old_func();

下面我就列出几个比较有用的(全部属性可参考GCC 文档),GCC 的属性都在 “gnu::” 里。

  • deprecated:与 C++14 相同,但可以用在 C++11 里。

  • unused:用于变量、类型、函数等,表示虽然暂时不用,但最好保留着,因为将来可能会用。

  • constructor:函数会在 main() 函数之前执行,效果有点像是全局对象的构造函数。

  • destructor:函数会在 main() 函数结束之后执行,有点像是全局对象的析构函数。

  • always_inline:要求编译器强制内联函数,作用比 inline 关键字更强。

  • hot:标记“热点”函数,要求编译器更积极地优化。

静态断言(static_assert)

static_assert 可以在编译阶段定义各种前置条件,充分利用 C++ 静态类型语言的优势,让编译器执行各种检查,避免把隐患带到运行阶段。

“静态断言”,static_assert (它是一个关键字),而不是宏。因为它只在编译时生效,运行阶段看不见,所以是“静态”的。它是编译阶段里检测各种条件的“断言”,编译器看到 static_assert 也会计算表达式的值,如果值是 false,就会报错,导致编译失败。

static_assert(
  sizeof(long) >= 8, "must run on x64");
  
static_assert(
  sizeof(int)  == 4, "int must be 32bit");

//下面的代码想检查空指针,由于变量只能在运行阶段出现,而在编译阶段不存在,所以静态断言无法处理。
char* p = nullptr;
static_assert(p == nullptr, "some error.");  // 错误用法

在泛型编程的时候,怎么检查模板类型呢?比如说,断言是整数而不是浮点数、断言是指针而不是引用、断言类型可拷贝可移动等等?

想要更好地发挥静态断言的威力,还要配合标准库里的“type_traits”,它提供了对应这些概念的各种编译期“函数”。

// 假设 T 是一个模板参数,即 template<typename T>
static_assert(
  is_integral<T>::value, "int");

static_assert(
  is_pointer<T>::value, "ptr");

static_assert(
  is_default_constructible<T>::value, "constructible");

相关文章

  • 编译阶段能做什么:属性和静态断言

    “编译阶段”的目标是生成计算机可识别的机器码。 编译是预处理之后的阶段,它的输入是(经过预处理的)C++ 源码,输...

  • TypeScript基础

    1、静态类型语言 和 动态类型语言 静态类型语言在编译阶段确定所有变量的类型在编译阶段确定属性偏移量用偏移量访问代...

  • Objective-C动态语言的特征体现在哪?

    1、静态和动态概念 静态:在程序编译阶段就能确定数据类型和所调用的方法;动态:将程序在编译阶段就能确定数据类型和所...

  • static_assert

    C++0x中引入了static_assert这个关键字,用来做编译期间的断言,因此叫做静态断言。 其语法很简单:s...

  • objective-c 动态数据类型

    静态数据类型 特点: 在编译时就知道变量的类型 知道变量中有哪些属性和方法 在编译的时候就可以访问这些属性和方法 ...

  • Spring AOP中的动态代理:JDK动态代理和CGLIB动态

    静态代理模式  所谓静态代理就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强。ApsectJ是静态...

  • 改善Java程序建议17

    建议 17: 慎用动态编译。 关于动态编译的代码: 只要静态编译能做的事情,动态编译就能实现。 动态编译时,需要注...

  • auto

    静态类型和类型检查。对于所谓的静态类型,类型检查主要发生在编译阶段;而对于动态类型,类型检查主要发生在运行阶段。这...

  • (实验)Swift 面向协议

    协议 swift中协议中可以声明属性,静态属性,方法,静态方案 子类如果继承了协议而不去实现其中的内容,编译就会通...

  • Java 静态属性与实例属性的初始化

    类的初始化包括静态属性的初始化和实例属性的初始化,在加载类过程中的准备阶段会给静态属性分配存储空间,并根据属性的类...

网友评论

      本文标题:编译阶段能做什么:属性和静态断言

      本文链接:https://www.haomeiwen.com/subject/lavjyltx.html