assert & static_assert

问题来源:statkoverflow What is the difference between assert and static_assert?

以下回答是对其的翻译

问题描述

我知道static_assert 是发生在编译期,assert是发生在运行时,那他们有什么不同呢?为什么不能使用if来检查呢?同样的问题我可以使用

1
2
3
4
if(condition == false) {
print(message);
exit();
}

有什么例子是只能使用assert或者static_assert的呢?

明明使用if更为简单为什么不实用if呢?

answer

只能使用static_assert的情况

但程序中的逻辑需要在编译期检查是否存在问题时,只能使用static_assert,因为此时if和assert还不能运行。

使用assert的情况

当你需要检查运行时代码是否有应该返回为一值的地方返回了预期之外的值,例如你要检查某个时刻某个位置的pointer的值是否为null,这个时候应该使用assert,为什么不是if呢?因为逻辑检查应该是存在于debug阶段的事情,在release时我们应该去除这类检查机制,如果使用if的话我们没有一个有效且快速去除它的方式。

const int* & int const*

问题来源: stack overflow What is the difference between const int*, const int * const, and int const *?

这确实是在我还是一个初学者的时候一直困扰着我的问题,到现在凭借经验倒是能区分这一问题,例如看const修饰的是type还是,当const修饰type是,那么这个value就是constant(不可变的),如果修饰的是\那么这个这个pointer就是不可变的。但是如果遇到如下定义,我还是要蒙好久或者干脆看不懂。

1
void (*signal(int, void (*fp)(int)))(int);

现在,有一个通用的解法能解释这个问题,原创作者是David Anderson,是早期C编译器的作者之一,以下内容是对其文章的翻译。

原文链接:The ``Clockwise/Spiral Rule’’

顺时针螺旋法则 Clockwise/Spiral Rule

这是一个关于C/C++类型声明的通用解释法则。

使用规则

最开始我们并不知道如何去解析这一元素,通过顺时针螺旋法则,我们可以将相关的类型声明翻译成通顺的中文句子(english statements),只需要通过如下三步

解析规则

[X] or []

​ ==>一个包含元素数量为X的数组

(type1,type2)

​ ==>传递参数为type1和type2返回值为…的函数

*

​ ==>指向类型为…的指针

螺旋解析

遵守顺时针螺旋法则直到所有的类型被解析完成

括号优先

总是先解析括号内的所有类型

案例1 简单的符号解析

1
char *str[10];
1
2
3
4
5
6
7
     +-------+
| +-+ |
| ^ | |
>char *str[10];
^ ^ | |
| +---+ |
+-----------+

根据如上提到的顺时针螺旋法则,我们知道先解析*[*,那么此处就应该是:

str是一个长度为10的数组

再接着旋转到了左边,我们遇到了*****,那此时再加上pointer就应该是:

str是一个长度为10的数组并且它的元素类型为指针类型

再接着旋转到右边,我们遇见了,不解释,咱继续旋转遇到了char,那么此时就应该是:

str是一个长度为10的数组并且它的数据类型为指针类型,指针指向的元素类型为char

案例2 函数指针解析

1
char *(*fp)( int, float *);
                +--------------------+
                | +---+              |
                | |+-+|              |
                | |^ ||              |
           char *(*fp)( int, float *);
            ^   ^ ^  ||              |
            |   | +--+|              |
            |   +-----+              |
            +------------------------+

我们先看()内,看见了一个*,那么fp就应该是:

一个指向类型待定的指针类型

接着旋转,我们又遇见了一个(),按照规则,优先解析()内的元素,那么fp就应该是:

一个指向函数的指针类型,该函数的参数有int,float,且返回值类型待定

接着旋转,我们遇到一个*,按照规则,那么fp就应该是:

一个指向函数的指针类型,该函数的参数有int,float,且返回值是指针类型,指向类型待定

继续旋转,遇到;,忽略,继续旋转,遇到了char,那么fp就应该是:

一个指向函数的指针类型,该函数的参数有int,float,且返回值是指针,指针指向的元素类型为char

案例3 究极复杂类型解析

1
void (*signal(int, void (*fp)(int)))(int);
1
2
3
4
5
6
7
8
9
      +-----------------------------+
| +---+ |
| +---+ |+-+| |
| ^ | |^ || |
void (*signal(int, void (*fp)(int)))(int);
^ ^ | ^ ^ || |
| +------+ | +--+| |
| +--------+ |
+----------------------------------+

首先我们看见了一个*,那signal应该是:

一个指针类型,且指向类型待定

然后我们又看见了一个fp(fp也在括号内),fp的类型是*,那么fp应该是:

一个指针类型,且指向类型待定

之后呢又看见了一个(),里面有一个int,那不出意外这fp应该是:

一个指针类型,且指向函数类型为参数类型为int,返回值类型待定

这是括号完了(signal里的括号完了),与fp相邻的还有void,因此确定了其返回值,这是fp应该是:

一个指针类型,且指向函数类型为参数类型为int,返回值类型为void

因为signal里面还有一个int,在加上去signal就应该是:

一个指针类型,且指向的函数第一个参数是int,第二个参数是一个指针类型,且指向函数类型为参数类型为int,返回值类型为void的函数指针

接着我们到了括号外面,我们又遇见了一个括号(int),那此时依旧解读成函数指针,由于篇幅原因我们快一点(带上void),那么signal就应该是:

一个指针类型,且指向的函数第一个参数是int,第二个参数是一个指针类型,且指向函数类型为参数类型为int,返回值类型为void的函数指针,且signal该函数指针的返回值是一个参数类型为int,返回值为void的函数指针类型

const int* & int* const & const int * const

根据以上规则,我们再来解读最开始的问题

const int * value;

value一个指针类型,且指向类型类型为int,并且这个int是一个const(常量)

int* const value;

value是一个const(常量),并且是一个指针类型,也就是常量指针类型,这个指针类型指向的类型是int

const int* const value;

value是一个const(常量),并且是一个指针类型,也就是常量指针类型,这个指针类型指向的类型是int,这个int也是一个常量。