读复杂的const声明的简单规则?

时间:2011-09-23 08:20:43

标签: c++ c const declaration

对于读取复杂指针声明,有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修饰符应指定该函数不操作此向量的字符串,并且不会更改向量的结构。

2 个答案:

答案 0 :(得分:61)

const修饰符很简单:它修改了它之前的内容,除非 没有什么先于它。所以:

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

等。一般来说,最好避免没有任何先例的形式 const,但在实践中,你会看到它们,所以你必须这样做 请记住,当const之前没有类型时,您必须逻辑上 把它移到第一种类型后面。所以:

const char** buffer;

实际上是:

char const** buffer;

,即指向const char的指针。

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

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

是:

char *const * argv,

指向char的const指针的指针。

答案 1 :(得分:6)

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

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是指向非const字符串指针的const向量的指针。

但人们会期待以下声明:

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

(指向常量字符串的const向量)

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

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

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

这意味着argv是指向const字符串的非const数组指针。

由于与上述相同的原因,人们会再次期待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;
}

不要。