c++ - 指针类型之间的转换规则,其中 cv 限定符是唯一的区别

标签 c++ constants volatile const-correctness c++98

这个问题特别与 C++98 有关,但如果您愿意,请随意提供任何与更新标准有关的有用信息。

如果您知道答案并想跳过其余部分,那么简短而有趣的是:

int **w;
int volatile*     *x = w; // error
int volatile*const*y = w; // OK
int const   *const*z = w; // OK    

为什么在 y 声明中,const 必须位于 volatile 的右侧?如果允许 x 的声明,某人可能会做出什么恶事?

在标准的 4.4.4 部分中,它说:

A conversion can add cv-qualifiers at levels other than the first in multi-level pointers, subject to the following rules:

Two pointer types T1 & T2 are similar if there exists a type T and integer n > 0 such that:

  • T1 is CV10 ptr to CV11 ptr to ... CV1N T
  • T2 is CV20 ptr to CV21 ptr to ... CV2N T

... where each CVij is const, volatile, const volatile, or nothing. The n-tuple of cv-qualifiers after the first in a pointer type, e.g., CV11, CV12, ..., CV1N in the pointer type T1, is called the cv-qualification signature of the pointer type. An expression of type T1 can be converted to type T2 iff the following conditions are satisfied:

  1. the pointer types are similar
  2. for every j > 0, if const is in CV1j, then const is in CV2j, and similarly for volatile.
  3. if the CV1j and CV2j are different, then const is in every CV2k for 0 < k < j

...之后,它继续给出将 ** 分配给 const** 的示例。上面的强调是我的,斜体来自文档。

将其放入代码中:

 int CV13* CV12* CV11* CV10 b1;
 int CV23* CV22* CV21* CV20 b2 = b1;

我对一些细节有点模糊......所以这里有一些问题或可能有缺陷的观察:

1) 上面写着除第一级以外的其他级别;对此不再详细说明,但 CV20 可以是任何有效的 CV 限定符。

2) 底部的第三条规则表示,如果 T2 在级别 j 添加 const volatile ,则级别 1 ... j-1 必须是 const (否则会遭受愤怒)。在下面,星星的数量与顶部的星星不同,以强调第三条规则的内容:

int *****w;
int **volatile*     *     *x = w; // error
int **volatile*const*const*y = w; // OK
int **const   *const*const*z = w; // OK

我明白为什么 z 需要它,但为什么 y 需要它? 4.4.4 中的示例大致如下,针对 volatile 情况进行了修改:

void f( int **x ) {
  int volatile**y = x; // not allowed
  // do some evil here
}

那里会放什么邪恶的东西?

最佳答案

(注意:“这个问题特别与 C++98 有关”,但在所有版本的标准中,过去和现在(我敢打赌 future 也是如此)的情况都是相同的,因为它本质上是关于 const-正确性并防止编码人员在类型系统中打开漏洞。)

由于标准使用通用术语“cv-qualifiers”,我发现仅使用“const”进行推理时更容易理解(没有“volatile ") [但请参阅下面的 volatile 示例]。 “C++ FAQ Lite”有一个相关条目:Why am I getting an error converting a Foo**Foo const**?

本质上,允许转换可以让您默默地修改const T(通过指向-const T的指针):

int const theAnswer = 42;
int* p = 0;  // int* p = &theAnswer; is not allowed of course...
int** pp = &p;
int const** ppc = pp;  // <-- Error, but imagine this were allowed...
*ppc = &theAnswer;  // &theAnswer is `int const*` and *ppc is `int const*` too,
                    // but it's also doing *pp = &theAnswer; i.e. p = &theAnswer;
*p = 999;  // I.e. theAnswer = 999; => modifying a const int!

但是通过添加“第一级”const,转换 int const* const* pcpc = pp; 是有效的,因为编译器会阻止您执行 >*pcpc = &theAnswer; (因为 *pcpcconst)。


编辑:对于 volatile ,问题可能不如const那么明显,但允许转换会让你默默地错误地访问(读或写)一个 volatile T,就好像它 volatile (通过指向- volatile T的指针):

extern int volatile externTimer;
int* p = 0;  // int* p = &externTimer; is not allowed...
int** pp = &p;
int volatile** ppv = pp;  // <-- Error, but imagine this were allowed...
*ppv = &externTimer;  // &externTimer is `int volatile*` and *ppv too,
                      // but it's also doing *pp = &externTimer; i.e. p = &externTimer;
int a1 = externTimer;  // First read
int a2 = externTimer;  // Second read, mandatory: the value may have changed externally
int b1 = *p;  // First read
int b2 = *p;  // Second read? may be optimized out! because *p is not volatile

但是通过添加“第一级”const,转换 int volatile* const* pcpv = pp; 是有效的,因为编译器会阻止您执行 >*pcpv = &externTimer; 之后(因为 *pcpvconst)。

关于c++ - 指针类型之间的转换规则,其中 cv 限定符是唯一的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17460149/

相关文章:

c++ - 如何减少 abs 函数的数量

c++ - _HUGE 和 __IMP__HUGE 在 "math.h"

是否可以将标签(分支目标)标记为 "volatile"以防止其被 GCC 优化触及?

c++ - 计算着色器 Open GL ES 的多个输入

javascript - C++、Qt、QtWebKit : How to create an html rendering window so that your application would get callbacks from JS calls?

c++ - 比较给定宽度和高度的纵横比

.net - 有没有更简单的方法在 .net 中创建注册表 volatile 子项?

c++ - 用 const 限定符更改替换方法 (C++)

c++ - 将常量传播到成员变量指向的数据

c++ - 指向非 volatile 数据的 volatile 指针