【问题标题】:Easy rule to read complicated const declarations?阅读复杂的 const 声明的简单规则?
【发布时间】:2011-11-23 11:29:43
【问题描述】:

对于读取复杂的指针声明,有right-left rule

但是这条规则没有提到如何阅读const修饰符。

例如在一个简单的指针声明中,const 可以通过多种方式应用:

char *buffer; // non-const pointer to non-const memory
const char *buffer; // non-const pointer to const memory
char const *buffer; // equivalent to previous declartion
char * const buffer = {0}; // const pointer to non-const memory
char * buffer const = {0}; // error
const char * const buffer = {0}; // const pointer to const memory

现在如何将const 与指针声明的指针一起使用?

char **x; // no const;
const char **x;
char * const *x;
char * * const x;
const char * const * x;
const char * * const x;
const char * const * const x;

阅读这些声明的简单规则是什么? 哪些声明有意义?

Clockwise/Spiral Rule 是否适用?

两个真实世界的例子

ASTUnit::LoadFromCommandLine 方法使用 const char ** 提供命令行参数(在 llvm clang 源中)。

getopt() 的实参向量参数声明如下:

int getopt(int argc, char * const argv[], const char *optstring);

在这种情况下,char * const argv[] 等同于 char * const * argv

由于两个函数使用相同的概念(一个指向字符串的向量来提供参数)并且声明不同 - 显而易见的问题是:为什么它们不同?一个比另一个更有意义?

意图应该是:const 修饰符应该指定函数不操作此向量的字符串并且不改变向量的结构。

【问题讨论】:

标签: c++ c constants declaration


【解决方案1】:

const 修饰符是微不足道的:它修改它之前的内容,除非 在它之前没有任何东西。所以:

char const* buffer;  // const modifies char
char* const buffer;  // const modifies *

等。一般情况下,最好避免前面没有任何内容的形式 const,但实际上,你会看到它们,所以你必须 请记住,当const 之前没有类型时,您必须在逻辑上 将其移到第一种类型的后面。所以:

const char** buffer;

其实是:

char const** buffer;

,即指向 const char 的指针。

最后,在函数声明中,[] after 读作 * before。 (同样,最好避免这种误导性的符号,但是 你会看到它,所以你必须处理它。)所以:

char * const argv[],  //  As function argument

是:

char *const * argv,

指向 const 的指针,指向 char。

【讨论】:

  • @Vorac 一种经常被引用的简化,它只适用于少数简单的情况。
  • James Kanze,如果你有时间,请在 quesion I opened 中解释这一点
【解决方案2】:

(试图关注问题的其他方面)

rule of thumb for const declarations 是从右到左读取它们,const 修改下一个标记。例外:在声明的开头const 修改了之前的标记。

有一个 rationale behind this exception - 用于基本声明 const char c 寻找比 char const c 更自然的一些人 - 据报道,const char c 的前体形式早于最终的 const 规则。

getopt

int getopt(int argc, char * const argv[], const char *optstring);

int getopt(int argc, char * const * argv, const char *optstring);

这意味着argv 是一个指向非常量字符串指针的常量向量的指针。

但人们会期望以下声明:

int getopt(int argc, char const * const * argv, const char *optstring);

(指向 const 向量的指针到 const 字符串)

因为getopt() 不应该更改通过 argv 引用的字符串。

至少char **(在main() 中使用)会自动转换为char * const * argv

叮当

ASTUnit::LoadFromCommandLine(...,  const char **argv, ...);

这意味着argv 是一个指向常量字符串指针的非常量数组的指针。

出于与上述相同的原因,人们再次期待const char * const *argv

但这更明显,因为char ** does not convertconst char **,例如

int main(int argc, char **argv) {
  const char **x = argv; // Compile error!
  return 0;
}

产生编译错误,其中

int main(int argc, char **argv) {
  char * const *x = argv;
  return 0;
}

int main(int argc, char **argv) {
  const char * const *x = argv;
  return 0;
}

不要。

【讨论】:

  • @bobc,我写的是“从右到左阅读它们”——即这是一个反向迭代。因此,“下一个”和“上一个”的选择是正确的。您似乎在前向迭代意义上解释了这些形容词-在该上下文/段落中没有任何意义。希望清除它。为什么你觉得这个平台很垃圾?因为像我这样的答案?还是像你这样的cmets?
猜你喜欢
  • 2016-02-26
  • 1970-01-01
  • 2019-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多