0
点赞
收藏
分享

微信扫一扫

【C++grammar】断言与表达式常量


目录

  • ​​1、常量表达式和constexpr关键字​​
  • ​​2、断言与C++11的静态断言​​
  • ​​1.1. assert : C语言的宏(Macro),运行时检测。​​
  • ​​1.2. assert()依赖于NDEBUG 宏​​
  • ​​1.3. assert 帮助调试解决逻辑bug (部分替代“断点/单步调试”)​​
  • ​​2.1static_assert (C++11的静态断言 )​​
  • ​​2.2. 作用:编译时断言检查​​
  • ​​2.3. static_assert的用途​​
  • ​​3. 1When to use assertions (何时使用断言)​​
  • ​​3、声明与定义​​
  • ​​1. What is "Declare/Declaration" (什么是声明)​​
  • ​​2. What is "define/definition" (什么是定义)​​
  • ​​3. Differences between a declaration and a definition (定义与声明的区别)​​


1、常量表达式和constexpr关键字

常量表达式是编译期间就能计算其结果的表达式。
const修饰的对象既可能是编译期常量,也可能是运行期常量。
constexpr说明符声明可在编译时计算函数或变量的值

constexpr int max(int a , int b) { // c++11 引入 constexpr
if (a > b) return a; // c++14才允许constexpr函数中有分支循环等
else return b;
}
int main() {
int m = 1;
const int rcm = m++; // rcm是运行期常量
const int cm = 4; // 编译期常量,等价于: constexpr int cm = 4;
int a1[ max(m , rcm)]; // 错误:m & rcm 不是编译期常量
std::array<char , max(cm , 5)> a2; // OK: cm 和 5 是编译期常量
}

const用来告知程序员const指向的内容不可被修改,主要目的是为了避免写出bug。
constexpr在所有编译期常量的地方做限定。使得constexpr修饰的语句在编译期即可计算得到值。让编译期优化代码性能。
constexpr修饰的函数,要满足什么条件才能成为编译期常量表达式?
constexpr 函数的返回值必须在编译时就能被确定。

2、断言与C++11的静态断言

断言是一条检测假设成立与否的语句。
断言assert是一个宏,而非一个函数。
static_assert 是一个关键字,而非一个函数。

1.1. assert : C语言的宏(Macro),运行时检测。

用法:包含头文件 以调试模式编译程序

//assert( bool_expr ); // bool_expr 为假则中断程序
std::array a{ 1, 2, 3 }; //C++17 类型参数推导
for (size_t i = 0; i <= a.size(); i++) {
assert(i < 3); //断言:i必须小于3,否则失败
std::cout << a[ i ];
std::cout << (i == a.size() ? "" : " ");

【C++grammar】断言与表达式常量_c++11

1.2. assert()依赖于NDEBUG 宏

NDEBUG这个宏是C/C++标准规定的,所有编译器都有对它的支持。
(1) 调试(Debug)模式编译时,编译器不会定义NDEBUG,所以assert()宏起作用。
(2) 发行(Release)模式编译时,编译器自动定义宏NDEBUG,使assert不起作用
如果要强制使得assert()生效或者使得assert()不生效,只要手动 #define NDEBUG 或者 #undef NDEBUG即可。

1.3. assert 帮助调试解决逻辑bug (部分替代“断点/单步调试”)

#undef NDEBUG   // 强制以debug模式使用<cassert>
int main() {
int i;
std::cout << "Enter an int: ";
std::cin >> i;
assert((i > 0) && "i must be positive");
return 0;
}

上面示例的第6行代码中,若assert中断了程序则表明程序出bug了!程序员要重编代码解决这个bug,而不是把assert()放在那里当成正常程序的一部分
assert断言中所用的表达式可以不是是编译期常量表达式。

2.1static_assert (C++11的静态断言 )

2.1. static_assert ( bool_constexpr, message)

其中两个参数解释如下:
(1) bool_constexpr: 编译期常量表达式,可转换为bool 类型
(2) message: 字符串字面量 ,是断言失败时显示的警告信息。自C++17起,message是可选的

2.2. 作用:编译时断言检查

// 下面的语句能够确保该程序在32位的平台上编译进行。
// 如果该程序在64位平台上编译,就会报错 (例子来自MSDN)

static_assert(sizeof(void *) == 4, "64-bit code generation is not supported.");

2.3. static_assert的用途

常用在模版编程中 ,对写库的作者用处大
在static_assert的第一个参数 bool_constexpr 中不能有变量表达式

3. 1When to use assertions (何时使用断言)

这里我们指的是assert,运行期的断言。
若某些状况是你预期中的,那么用错误处理;若某些状况永不该发生,用断言)

int n{ 1 } , m{ 0 };
std::cin >> n;
assert((n != 0) && "Divisor cannot be zero!"); // 不合适
int q = m / n;
int n{ 1 } , m{ 0 };
do { // 这是修补bug的代码
std::cin >> n; // 断言失败后,要解决这个bug
} while (n == 0); // 在这里编写修复bug的代码
assert((n != 0) && "Divisor cannot be zero!");
int q = m / n;

下面的例子说明了在编译期,静态断言就已经执行了,因为array<int,nums>的nums在编译期就应该知道它的值。
【C++grammar】断言与表达式常量_编程语言_02

3、声明与定义

1. What is “Declare/Declaration” (什么是声明)

“声明”是引入标识符并描述其类型,无论是类型,对象还是函数。编译器需要该“声明”,以便识别在它处使用该标识符。

extern int bar;

extern int g(int, int);

double f(int, double); // extern can be omitted for function declarations

class foo; // no extern allowed for type declarations

2. What is “define/definition” (什么是定义)

“定义”实例化/实现这个标识符。链接器需要“定义”,以便将对标识符的引用链接到标识符所表示的实体。

int bar;

int g(int lhs, int rhs) {return lhs*rhs;}

double f(int i, double d) {return i+d;}

class foo {};

3. Differences between a declaration and a definition (定义与声明的区别)

1、定义有时可取代声明,反之则不行
2、标识符可被声明多次,但只能定义一次
3、 定义通常伴随着编译器为标识符分配内存


举报

相关推荐

0 条评论